1 /* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
2 * xscreensaver, Copyright (c) 1993-1999 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
17 #ifdef HAVE_GTK /* whole file */
26 # include <pwd.h> /* for getpwuid() */
32 # include <sys/utsname.h> /* for uname() */
33 #endif /* HAVE_UNAME */
37 #include <X11/Xproto.h> /* for CARD32 */
38 #include <X11/Xatom.h> /* for XA_INTEGER */
39 #include <X11/Intrinsic.h>
40 #include <X11/StringDefs.h>
42 /* We don't actually use any widget internals, but these are included
43 so that gdb will have debug info for the widgets... */
44 #include <X11/IntrinsicP.h>
45 #include <X11/ShellP.h>
49 # include <X11/Xmu/Error.h>
51 # include <Xmu/Error.h>
61 extern Display *gdk_display;
65 #include "resources.h" /* for parse_time() */
66 #include "visual.h" /* for has_writable_cells() */
67 #include "remote.h" /* for xscreensaver_command() */
70 #include "demo-Gtk-widgets.h"
77 #define countof(x) (sizeof((x))/sizeof((*x)))
81 char *progclass = "XScreenSaver";
85 saver_preferences *a, *b;
88 static void *global_prefs_pair; /* I hate C so much... */
90 char *blurb (void) { return progname; }
92 static char *short_version = 0;
95 Atom XA_SCREENSAVER, XA_SCREENSAVER_RESPONSE, XA_SCREENSAVER_VERSION;
96 Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_SELECT, XA_DEMO;
97 Atom XA_ACTIVATE, XA_BLANK, XA_LOCK, XA_RESTART, XA_EXIT;
100 static void populate_demo_window (GtkWidget *toplevel,
101 int which, prefs_pair *pair);
102 static void populate_prefs_page (GtkWidget *top, prefs_pair *pair);
103 static int apply_changes_and_save (GtkWidget *widget);
104 static int maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair);
107 /* Some random utility functions
111 name_to_widget (GtkWidget *widget, const char *name)
115 GtkWidget *parent = (GTK_IS_MENU (widget)
116 ? gtk_menu_get_attach_widget (GTK_MENU (widget))
123 return (GtkWidget *) gtk_object_get_data (GTK_OBJECT (widget), name);
128 /* Why this behavior isn't automatic in *either* toolkit, I'll never know.
129 Takes a scroller, viewport, or list as an argument.
132 ensure_selected_item_visible (GtkWidget *widget)
134 GtkScrolledWindow *scroller = 0;
136 GtkList *list_widget = 0;
140 GtkWidget *selected = 0;
143 gint parent_h, child_y, child_h, children_h, ignore;
144 double ratio_t, ratio_b;
146 if (GTK_IS_SCROLLED_WINDOW (widget))
148 scroller = GTK_SCROLLED_WINDOW (widget);
149 vp = GTK_VIEWPORT (GTK_BIN (scroller)->child);
150 list_widget = GTK_LIST (GTK_BIN(vp)->child);
152 else if (GTK_IS_VIEWPORT (widget))
154 vp = GTK_VIEWPORT (widget);
155 scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
156 list_widget = GTK_LIST (GTK_BIN(vp)->child);
158 else if (GTK_IS_LIST (widget))
160 list_widget = GTK_LIST (widget);
161 vp = GTK_VIEWPORT (GTK_WIDGET (list_widget)->parent);
162 scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
167 slist = list_widget->selection;
168 selected = (slist ? GTK_WIDGET (slist->data) : 0);
172 which = gtk_list_child_position (list_widget, GTK_WIDGET (selected));
174 for (kids = gtk_container_children (GTK_CONTAINER (list_widget));
175 kids; kids = kids->next)
178 adj = gtk_scrolled_window_get_vadjustment (scroller);
180 gdk_window_get_geometry (GTK_WIDGET(vp)->window,
181 &ignore, &ignore, &ignore, &parent_h, &ignore);
182 gdk_window_get_geometry (GTK_WIDGET(selected)->window,
183 &ignore, &child_y, &ignore, &child_h, &ignore);
184 children_h = nkids * child_h;
186 ratio_t = ((double) child_y) / ((double) children_h);
187 ratio_b = ((double) child_y + child_h) / ((double) children_h);
189 if (adj->upper == 0.0) /* no items in list */
192 if (ratio_t < (adj->value / adj->upper) ||
193 ratio_b > ((adj->value + adj->page_size) / adj->upper))
196 int slop = parent_h * 0.75; /* how much to overshoot by */
198 if (ratio_t < (adj->value / adj->upper))
200 double ratio_w = ((double) parent_h) / ((double) children_h);
201 double ratio_l = (ratio_b - ratio_t);
202 target = ((ratio_t - ratio_w + ratio_l) * adj->upper);
205 else /* if (ratio_b > ((adj->value + adj->page_size) / adj->upper))*/
207 target = ratio_t * adj->upper;
211 if (target > adj->upper - adj->page_size)
212 target = adj->upper - adj->page_size;
216 gtk_adjustment_set_value (adj, target);
222 warning_dialog_dismiss_cb (GtkButton *button, gpointer user_data)
224 GtkWidget *shell = GTK_WIDGET (user_data);
225 while (shell->parent)
226 shell = shell->parent;
227 gtk_widget_destroy (GTK_WIDGET (shell));
232 warning_dialog (GtkWidget *parent, const char *message, int center)
234 char *msg = strdup (message);
237 GtkWidget *dialog = gtk_dialog_new ();
238 GtkWidget *label = 0;
242 while (parent->parent)
243 parent = parent->parent;
249 char *s = strchr (head, '\n');
252 sprintf (name, "label%d", i++);
256 label = gtk_label_new (head);
257 sprintf (buf, "warning_dialog.%s.font", name);
258 GTK_WIDGET (label)->style = gtk_style_copy (GTK_WIDGET (label)->style);
259 GTK_WIDGET (label)->style->font =
260 gdk_font_load (get_string_resource (buf, "Dialog.Label.Font"));
262 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
263 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
264 label, TRUE, TRUE, 0);
265 gtk_widget_show (label);
276 label = gtk_label_new ("");
277 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
278 label, TRUE, TRUE, 0);
279 gtk_widget_show (label);
281 label = gtk_hbutton_box_new ();
282 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
283 label, TRUE, TRUE, 0);
285 ok = gtk_button_new_with_label ("OK");
286 gtk_container_add (GTK_CONTAINER (label), ok);
288 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
289 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
290 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
291 gtk_widget_show (ok);
292 gtk_widget_show (label);
293 gtk_widget_show (dialog);
294 /* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
296 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
297 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
299 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
300 GTK_WIDGET (parent)->window);
302 gdk_window_show (GTK_WIDGET (dialog)->window);
303 gdk_window_raise (GTK_WIDGET (dialog)->window);
310 run_cmd (GtkWidget *widget, Atom command, int arg)
315 apply_changes_and_save (widget);
316 status = xscreensaver_command (gdk_display, command, arg, False, &err);
321 sprintf (buf, "Error:\n\n%s", err);
323 strcpy (buf, "Unknown error!");
324 warning_dialog (widget, buf, 100);
331 run_hack (GtkWidget *widget, int which, Bool report_errors_p)
333 if (which < 0) return;
334 apply_changes_and_save (widget);
336 run_cmd (widget, XA_DEMO, which + 1);
340 xscreensaver_command (gdk_display, XA_DEMO, which + 1, False, &s);
351 exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
353 apply_changes_and_save (GTK_WIDGET (menuitem));
358 wm_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
360 apply_changes_and_save (widget);
366 cut_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
369 warning_dialog (GTK_WIDGET (menuitem),
371 "cut unimplemented\n", 1);
376 copy_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
379 warning_dialog (GTK_WIDGET (menuitem),
381 "copy unimplemented\n", 1);
386 paste_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
389 warning_dialog (GTK_WIDGET (menuitem),
391 "paste unimplemented\n", 1);
396 about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
399 char *s = strdup (screensaver_id + 4);
402 s2 = strchr (s, ',');
406 sprintf (buf, "%s\n%s\n\n"
407 "For updates, check http://www.jwz.org/xscreensaver/",
411 warning_dialog (GTK_WIDGET (menuitem), buf, 100);
416 doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
418 /* prefs_pair *pair = (prefs_pair *) client_data; */
419 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
421 saver_preferences *p = pair->a;
424 if (!p->help_url || !*p->help_url)
426 warning_dialog (GTK_WIDGET (menuitem),
428 "No Help URL has been specified.\n", 100);
432 help_command = (char *) malloc (strlen (p->load_url_command) +
433 (strlen (p->help_url) * 2) + 20);
434 strcpy (help_command, "( ");
435 sprintf (help_command + strlen(help_command),
436 p->load_url_command, p->help_url, p->help_url);
437 strcat (help_command, " ) &");
438 system (help_command);
444 activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
446 run_cmd (GTK_WIDGET (menuitem), XA_ACTIVATE, 0);
451 lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
453 run_cmd (GTK_WIDGET (menuitem), XA_LOCK, 0);
458 kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
460 run_cmd (GTK_WIDGET (menuitem), XA_EXIT, 0);
465 restart_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
468 run_cmd (GTK_WIDGET (menuitem), XA_RESTART, 0);
470 apply_changes_and_save (GTK_WIDGET (menuitem));
471 xscreensaver_command (gdk_display, XA_EXIT, 0, False, NULL);
473 system ("xscreensaver -nosplash &");
478 static int _selected_hack_number = -1;
481 selected_hack_number (GtkWidget *toplevel)
484 GtkViewport *vp = GTK_VIEWPORT (name_to_widget (toplevel, "viewport"));
485 GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
486 GList *slist = list_widget->selection;
487 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
488 int which = (selected
489 ? gtk_list_child_position (list_widget, GTK_WIDGET (selected))
493 return _selected_hack_number;
499 demo_write_init_file (GtkWidget *widget, saver_preferences *p)
501 if (!write_init_file (p, short_version, False))
505 const char *f = init_file_name();
507 warning_dialog (widget,
508 "Error:\n\nCouldn't determine init file name!\n",
512 char *b = (char *) malloc (strlen(f) + 1024);
513 sprintf (b, "Error:\n\nCouldn't write %s\n", f);
514 warning_dialog (widget, b, 100);
523 apply_changes_and_save (GtkWidget *widget)
525 /* prefs_pair *pair = (prefs_pair *) client_data; */
526 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
527 saver_preferences *p = pair->a;
528 GtkList *list_widget =
529 GTK_LIST (name_to_widget (widget, "list"));
530 int which = selected_hack_number (widget);
532 GtkEntry *cmd = GTK_ENTRY (name_to_widget (widget, "cmd_text"));
533 GtkToggleButton *enabled =
534 GTK_TOGGLE_BUTTON (name_to_widget (widget, "enabled"));
535 GtkCombo *vis = GTK_COMBO (name_to_widget (widget, "visual_combo"));
537 Bool enabled_p = gtk_toggle_button_get_active (enabled);
538 const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
539 const char *command = gtk_entry_get_text (cmd);
544 if (which < 0) return -1;
546 if (maybe_reload_init_file (widget, pair) != 0)
549 /* Sanity-check and canonicalize whatever the user typed into the combo box.
551 if (!strcasecmp (visual, "")) visual = "";
552 else if (!strcasecmp (visual, "any")) visual = "";
553 else if (!strcasecmp (visual, "default")) visual = "Default";
554 else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
555 else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
556 else if (!strcasecmp (visual, "best")) visual = "Best";
557 else if (!strcasecmp (visual, "mono")) visual = "Mono";
558 else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
559 else if (!strcasecmp (visual, "gray")) visual = "Gray";
560 else if (!strcasecmp (visual, "grey")) visual = "Gray";
561 else if (!strcasecmp (visual, "color")) visual = "Color";
562 else if (!strcasecmp (visual, "gl")) visual = "GL";
563 else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
564 else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
565 else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
566 else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
567 else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
568 else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
569 else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
570 else if (1 == sscanf (visual, " %ld %c", &id, &c)) ;
571 else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
574 gdk_beep (); /* unparsable */
576 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");
579 ensure_selected_item_visible (GTK_WIDGET (list_widget));
581 if (!p->screenhacks[which]->visual)
582 p->screenhacks[which]->visual = strdup ("");
583 if (!p->screenhacks[which]->command)
584 p->screenhacks[which]->command = strdup ("");
586 if (p->screenhacks[which]->enabled_p != enabled_p ||
587 !!strcasecmp (p->screenhacks[which]->visual, visual) ||
588 !!strcasecmp (p->screenhacks[which]->command, command))
590 /* Something was changed -- store results into the struct,
593 free (p->screenhacks[which]->visual);
594 free (p->screenhacks[which]->command);
595 p->screenhacks[which]->visual = strdup (visual);
596 p->screenhacks[which]->command = strdup (command);
597 p->screenhacks[which]->enabled_p = enabled_p;
599 return demo_write_init_file (widget, p);
602 /* No changes made */
607 run_this_cb (GtkButton *button, gpointer user_data)
609 int which = selected_hack_number (GTK_WIDGET (button));
610 if (which < 0) return;
611 if (0 == apply_changes_and_save (GTK_WIDGET (button)))
612 run_hack (GTK_WIDGET (button), which, True);
617 manual_cb (GtkButton *button, gpointer user_data)
619 /* prefs_pair *pair = (prefs_pair *) client_data; */
620 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
621 saver_preferences *p = pair->a;
622 GtkList *list_widget =
623 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
624 int which = selected_hack_number (GTK_WIDGET (button));
625 char *name, *name2, *cmd, *s;
626 if (which < 0) return;
627 apply_changes_and_save (GTK_WIDGET (button));
628 ensure_selected_item_visible (GTK_WIDGET (list_widget));
630 name = strdup (p->screenhacks[which]->command);
632 while (isspace (*name2)) name2++;
634 while (*s && !isspace (*s)) s++;
636 s = strrchr (name2, '/');
639 cmd = get_string_resource ("manualCommand", "ManualCommand");
642 char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
644 sprintf (cmd2 + strlen (cmd2),
646 name2, name2, name2, name2);
647 strcat (cmd2, " ) &");
653 warning_dialog (GTK_WIDGET (button),
654 "Error:\n\nno `manualCommand' resource set.",
663 run_next_cb (GtkButton *button, gpointer user_data)
665 /* prefs_pair *pair = (prefs_pair *) client_data; */
666 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
667 saver_preferences *p = pair->a;
669 GtkList *list_widget =
670 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
671 int which = selected_hack_number (GTK_WIDGET (button));
678 if (which >= p->screenhacks_count)
681 apply_changes_and_save (GTK_WIDGET (button));
682 gtk_list_select_item (GTK_LIST (list_widget), which);
683 ensure_selected_item_visible (GTK_WIDGET (list_widget));
684 populate_demo_window (GTK_WIDGET (button), which, pair);
685 run_hack (GTK_WIDGET (button), which, False);
690 run_prev_cb (GtkButton *button, gpointer user_data)
692 /* prefs_pair *pair = (prefs_pair *) client_data; */
693 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
694 saver_preferences *p = pair->a;
696 GtkList *list_widget =
697 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
698 int which = selected_hack_number (GTK_WIDGET (button));
701 which = p->screenhacks_count - 1;
706 which = p->screenhacks_count - 1;
708 apply_changes_and_save (GTK_WIDGET (button));
709 gtk_list_select_item (GTK_LIST (list_widget), which);
710 ensure_selected_item_visible (GTK_WIDGET (list_widget));
711 populate_demo_window (GTK_WIDGET (button), which, pair);
712 run_hack (GTK_WIDGET (button), which, False);
716 /* Helper for the text fields that contain time specifications:
717 this parses the text, and does error checking.
720 hack_time_text (GtkWidget *widget, const char *line, Time *store, Bool sec_p)
725 value = parse_time ((char *) line, sec_p, True);
726 value *= 1000; /* Time measures in microseconds */
732 "Unparsable time format: \"%s\"\n",
734 warning_dialog (widget, b, 100);
743 prefs_ok_cb (GtkButton *button, gpointer user_data)
745 /* prefs_pair *pair = (prefs_pair *) client_data; */
746 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
748 saver_preferences *p = pair->a;
749 saver_preferences *p2 = pair->b;
750 Bool changed = False;
752 # define SECONDS(field, name) \
753 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
754 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
758 # define MINUTES(field, name) \
759 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
760 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
764 # define INTEGER(field, name) do { \
765 char *line = gtk_entry_get_text (\
766 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
767 unsigned int value; \
771 else if (sscanf (line, "%u%c", &value, &c) != 1) \
774 sprintf (b, "Error:\n\n" "Not an integer: \"%s\"\n", line); \
775 warning_dialog (GTK_WIDGET (button), b, 100); \
781 # define CHECKBOX(field, name) \
782 field = gtk_toggle_button_get_active (\
783 GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET(button), (name))))
785 MINUTES (&p2->timeout, "timeout_text");
786 MINUTES (&p2->cycle, "cycle_text");
787 SECONDS (&p2->fade_seconds, "fade_text");
788 INTEGER (&p2->fade_ticks, "ticks_text");
789 MINUTES (&p2->lock_timeout, "lock_text");
790 SECONDS (&p2->passwd_timeout, "pass_text");
791 CHECKBOX (p2->verbose_p, "verbose_button");
792 CHECKBOX (p2->install_cmap_p, "install_button");
793 CHECKBOX (p2->fade_p, "fade_button");
794 CHECKBOX (p2->unfade_p, "unfade_button");
795 CHECKBOX (p2->lock_p, "lock_button");
802 # define COPY(field) \
803 if (p->field != p2->field) changed = True; \
809 COPY(passwd_timeout);
813 COPY(install_cmap_p);
819 populate_prefs_page (GTK_WIDGET (button), pair);
822 demo_write_init_file (GTK_WIDGET (button), p);
827 prefs_cancel_cb (GtkButton *button, gpointer user_data)
829 /* prefs_pair *pair = (prefs_pair *) client_data; */
830 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
833 populate_prefs_page (GTK_WIDGET (button), pair);
838 list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
839 gpointer client_data)
841 if (event->type == GDK_2BUTTON_PRESS)
843 GtkList *list = GTK_LIST (name_to_widget (button, "list"));
844 int which = gtk_list_child_position (list, GTK_WIDGET (button));
847 run_hack (GTK_WIDGET (button), which, True);
855 list_select_cb (GtkList *list, GtkWidget *child)
857 /* prefs_pair *pair = (prefs_pair *) client_data; */
858 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
860 int which = gtk_list_child_position (list, GTK_WIDGET (child));
861 apply_changes_and_save (GTK_WIDGET (list));
862 populate_demo_window (GTK_WIDGET (list), which, pair);
866 list_unselect_cb (GtkList *list, GtkWidget *child)
868 /* prefs_pair *pair = (prefs_pair *) client_data; */
869 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
871 apply_changes_and_save (GTK_WIDGET (list));
872 populate_demo_window (GTK_WIDGET (list), -1, pair);
876 /* Populating the various widgets
880 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
883 format_time (char *buf, Time time)
886 unsigned int h = 0, m = 0;
897 sprintf (buf, "%u:%02u:%02u", h, m, s);
902 make_pretty_name (const char *shell_command)
904 char *s = strdup (shell_command);
908 for (s2 = s; *s2; s2++) /* truncate at first whitespace */
915 s2 = strrchr (s, '/'); /* if pathname, take last component */
923 if (strlen (s) > 50) /* 51 is hereby defined as "unreasonable" */
926 sprintf (res_name, "hacks.%s.name", s); /* resource? */
927 s2 = get_string_resource (res_name, res_name);
931 for (s2 = s; *s2; s2++) /* if it has any capitals, return it */
932 if (*s2 >= 'A' && *s2 <= 'Z')
935 if (s[0] >= 'a' && s[0] <= 'z') /* else cap it */
937 if (s[0] == 'X' && s[1] >= 'a' && s[1] <= 'z') /* (magic leading X) */
943 /* Finds the number of the last hack to run, and makes that item be
947 scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
949 saver_preferences *p = pair->a;
952 unsigned long nitems, bytesafter;
954 Display *dpy = gdk_display;
958 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
959 XA_SCREENSAVER_STATUS,
960 0, 3, False, XA_INTEGER,
961 &type, &format, &nitems, &bytesafter,
962 (unsigned char **) &data)
964 && type == XA_INTEGER
967 which = (int) data[2] - 1;
969 if (data) free (data);
974 list = GTK_LIST (name_to_widget (toplevel, "list"));
975 apply_changes_and_save (toplevel);
976 if (which < p->screenhacks_count)
978 gtk_list_select_item (list, which);
979 ensure_selected_item_visible (GTK_WIDGET (list));
980 populate_demo_window (toplevel, which, pair);
987 populate_hack_list (GtkWidget *toplevel, prefs_pair *pair)
989 saver_preferences *p = pair->a;
990 GtkList *list = GTK_LIST (name_to_widget (toplevel, "list"));
991 screenhack **hacks = p->screenhacks;
994 for (h = hacks; h && *h; h++)
997 char *pretty_name = (h[0]->name
998 ? strdup (h[0]->name)
999 : make_pretty_name (h[0]->command));
1001 line = gtk_list_item_new_with_label (pretty_name);
1004 gtk_container_add (GTK_CONTAINER (list), line);
1005 gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
1006 GTK_SIGNAL_FUNC (list_doubleclick_cb),
1009 GTK_WIDGET (GTK_BIN(line)->child)->style =
1010 gtk_style_copy (GTK_WIDGET (text_line)->style);
1012 gtk_widget_show (line);
1015 gtk_signal_connect (GTK_OBJECT (list), "select_child",
1016 GTK_SIGNAL_FUNC (list_select_cb),
1018 gtk_signal_connect (GTK_OBJECT (list), "unselect_child",
1019 GTK_SIGNAL_FUNC (list_unselect_cb),
1025 populate_prefs_page (GtkWidget *top, prefs_pair *pair)
1027 saver_preferences *p = pair->a;
1030 format_time (s, p->timeout);
1031 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "timeout_text")), s);
1032 format_time (s, p->cycle);
1033 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "cycle_text")), s);
1034 format_time (s, p->lock_timeout);
1035 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "lock_text")), s);
1036 format_time (s, p->passwd_timeout);
1037 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "pass_text")), s);
1038 format_time (s, p->fade_seconds);
1039 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "fade_text")), s);
1040 sprintf (s, "%u", p->fade_ticks);
1041 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "ticks_text")), s);
1043 gtk_toggle_button_set_active (
1044 GTK_TOGGLE_BUTTON (name_to_widget (top, "verbose_button")),
1046 gtk_toggle_button_set_active (
1047 GTK_TOGGLE_BUTTON (name_to_widget (top, "install_button")),
1049 gtk_toggle_button_set_active (
1050 GTK_TOGGLE_BUTTON (name_to_widget (top, "fade_button")),
1052 gtk_toggle_button_set_active (
1053 GTK_TOGGLE_BUTTON (name_to_widget (top, "unfade_button")),
1055 gtk_toggle_button_set_active (
1056 GTK_TOGGLE_BUTTON (name_to_widget (top, "lock_button")),
1061 Bool found_any_writable_cells = False;
1062 Display *dpy = gdk_display;
1063 int nscreens = ScreenCount(dpy);
1065 for (i = 0; i < nscreens; i++)
1067 Screen *s = ScreenOfDisplay (dpy, i);
1068 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1070 found_any_writable_cells = True;
1075 gtk_widget_set_sensitive (
1076 GTK_WIDGET (name_to_widget (top, "fade_label")),
1077 found_any_writable_cells);
1078 gtk_widget_set_sensitive (
1079 GTK_WIDGET (name_to_widget (top, "ticks_label")),
1080 found_any_writable_cells);
1081 gtk_widget_set_sensitive (
1082 GTK_WIDGET (name_to_widget (top, "fade_text")),
1083 found_any_writable_cells);
1084 gtk_widget_set_sensitive (
1085 GTK_WIDGET (name_to_widget (top, "ticks_text")),
1086 found_any_writable_cells);
1087 gtk_widget_set_sensitive (
1088 GTK_WIDGET (name_to_widget (top, "install_button")),
1089 found_any_writable_cells);
1090 gtk_widget_set_sensitive (
1091 GTK_WIDGET (name_to_widget (top, "fade_button")),
1092 found_any_writable_cells);
1093 gtk_widget_set_sensitive (
1094 GTK_WIDGET (name_to_widget (top, "unfade_button")),
1095 found_any_writable_cells);
1102 sensitize_demo_widgets (GtkWidget *toplevel, Bool sensitive_p)
1104 const char *names[] = { "cmd_label", "cmd_text", "enabled",
1105 "visual", "visual_combo",
1108 for (i = 0; i < countof(names); i++)
1110 GtkWidget *w = name_to_widget (toplevel, names[i]);
1111 gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
1114 /* I don't know how to handle these yet... */
1116 const char *names2[] = { "cut_menu", "copy_menu", "paste_menu" };
1117 for (i = 0; i < countof(names2); i++)
1119 GtkWidget *w = name_to_widget (toplevel, names2[i]);
1120 gtk_widget_set_sensitive (GTK_WIDGET(w), False);
1126 /* Even though we've given these text fields a maximum number of characters,
1127 their default size is still about 30 characters wide -- so measure out
1128 a string in their font, and resize them to just fit that.
1131 fix_text_entry_sizes (GtkWidget *toplevel)
1133 const char *names[] = { "timeout_text", "cycle_text", "fade_text",
1134 "ticks_text", "lock_text", "pass_text" };
1139 for (i = 0; i < countof(names); i++)
1141 w = GTK_WIDGET (name_to_widget (toplevel, names[i]));
1143 width = gdk_text_width (w->style->font, "00:00:00_", 9);
1144 gtk_widget_set_usize (w, width, -2);
1147 /* Now fix the size of the combo box.
1149 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "visual_combo"));
1150 w = GTK_COMBO (w)->entry;
1151 width = gdk_text_width (w->style->font, "PseudoColor___", 14);
1152 gtk_widget_set_usize (w, width, -2);
1155 /* Now fix the size of the list.
1157 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "list"));
1158 width = gdk_text_width (w->style->font, "nnnnnnnnnnnnnnnnnnnnnn", 22);
1159 gtk_widget_set_usize (w, width, -2);
1166 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...)
1169 static char *up_arrow_xpm[] = {
1192 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1193 the end of the array (Gtk 1.2.5.) */
1194 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1195 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1198 static char *down_arrow_xpm[] = {
1221 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1222 the end of the array (Gtk 1.2.5.) */
1223 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1224 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1228 pixmapify_buttons (GtkWidget *toplevel)
1232 GtkWidget *pixmapwid;
1236 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "next"));
1237 style = gtk_widget_get_style (w);
1239 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1240 &style->bg[GTK_STATE_NORMAL],
1241 (gchar **) down_arrow_xpm);
1242 pixmapwid = gtk_pixmap_new (pixmap, mask);
1243 gtk_widget_show (pixmapwid);
1244 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1245 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1247 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "prev"));
1248 style = gtk_widget_get_style (w);
1250 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1251 &style->bg[GTK_STATE_NORMAL],
1252 (gchar **) up_arrow_xpm);
1253 pixmapwid = gtk_pixmap_new (pixmap, mask);
1254 gtk_widget_show (pixmapwid);
1255 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1256 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1261 /* Work around a Gtk bug that causes label widgets to wrap text too early.
1265 you_are_not_a_unique_or_beautiful_snowflake (GtkWidget *label,
1266 GtkAllocation *allocation,
1270 GtkWidgetAuxInfo *aux_info;
1272 aux_info = gtk_object_get_data (GTK_OBJECT (label), "gtk-aux-info");
1274 aux_info->width = allocation->width;
1275 aux_info->height = -2;
1279 gtk_widget_size_request (label, &req);
1283 /* Feel the love. Thanks to Nat Friedman for finding this workaround.
1286 eschew_gtk_lossage (GtkWidget *toplevel)
1288 GtkWidgetAuxInfo *aux_info;
1289 GtkWidget *label = GTK_WIDGET (name_to_widget (toplevel, "doc"));
1291 aux_info = g_new0 (GtkWidgetAuxInfo, 1);
1292 aux_info->width = label->allocation.width;
1293 aux_info->height = -2;
1297 gtk_object_set_data (GTK_OBJECT (label), "gtk-aux-info", aux_info);
1299 gtk_signal_connect (GTK_OBJECT (label), "size_allocate",
1300 you_are_not_a_unique_or_beautiful_snowflake, NULL);
1302 gtk_widget_queue_resize (label);
1307 get_hack_blurb (screenhack *hack)
1310 char *prog_name = strdup (hack->command);
1311 char *pretty_name = (hack->name
1312 ? strdup (hack->name)
1313 : make_pretty_name (hack->command));
1314 char doc_name[255], doc_class[255];
1317 for (s = prog_name; *s && !isspace(*s); s++)
1320 s = strrchr (prog_name, '/');
1321 if (s) strcpy (prog_name, s+1);
1323 sprintf (doc_name, "hacks.%s.documentation", pretty_name);
1324 sprintf (doc_class, "hacks.%s.documentation", prog_name);
1328 doc_string = get_string_resource (doc_name, doc_class);
1331 for (s = doc_string; *s; s++)
1335 /* skip over whitespace at beginning of line */
1337 while (*s && (*s == ' ' || *s == '\t'))
1340 else if (*s == ' ' || *s == '\t')
1342 /* compress all other horizontal whitespace. */
1345 for (s2 = s; *s2 && (*s2 == ' ' || *s2 == '\t'); s2++)
1347 if (s2 > s) strcpy (s, s2);
1352 while (*s && isspace (*s)) /* Strip trailing whitespace */
1355 /* Delete whitespace at end of each line. */
1356 for (; s > doc_string; s--)
1357 if (*s == '\n' && (s[-1] == ' ' || s[-1] == '\t'))
1360 s2 > doc_string && (*s2 == ' ' || *s2 == '\t');
1364 if (s2 < s) strcpy (s2, s);
1368 /* Delete leading blank lines. */
1369 for (s = doc_string; *s == '\n'; s++)
1371 if (s > doc_string) strcpy (doc_string, s);
1375 static int doc_installed = 0;
1376 if (doc_installed == 0)
1378 if (get_boolean_resource ("hacks.documentation.isInstalled",
1379 "hacks.documentation.isInstalled"))
1385 if (doc_installed < 0)
1387 strdup ("Error:\n\n"
1388 "The documentation strings do not appear to be "
1389 "installed. This is probably because there is "
1390 "an \"XScreenSaver\" app-defaults file installed "
1391 "that is from an older version of the program. "
1392 "To fix this problem, delete that file, or "
1393 "install a current version (either will work.)");
1395 doc_string = strdup ("");
1403 populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
1405 saver_preferences *p = pair->a;
1406 screenhack *hack = (which >= 0 && which < p->screenhacks_count
1407 ? p->screenhacks[which] : 0);
1408 GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
1409 GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
1410 GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
1411 GtkToggleButton *enabled =
1412 GTK_TOGGLE_BUTTON (name_to_widget (toplevel, "enabled"));
1413 GtkCombo *vis = GTK_COMBO (name_to_widget (toplevel, "visual_combo"));
1415 char *pretty_name = (hack
1417 ? strdup (hack->name)
1418 : make_pretty_name (hack->command))
1420 char *doc_string = hack ? get_hack_blurb (hack) : 0;
1422 gtk_frame_set_label (frame, (pretty_name ? pretty_name : ""));
1423 gtk_label_set_text (doc, (doc_string ? doc_string : ""));
1424 gtk_entry_set_text (cmd, (hack ? hack->command : ""));
1425 gtk_entry_set_position (cmd, 0);
1426 gtk_toggle_button_set_active (enabled, (hack ? hack->enabled_p : False));
1427 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry),
1429 ? (hack->visual && *hack->visual
1434 gtk_container_resize_children (GTK_CONTAINER (GTK_WIDGET (doc)->parent));
1436 sensitize_demo_widgets (toplevel, (hack ? True : False));
1438 if (pretty_name) free (pretty_name);
1439 if (doc_string) free (doc_string);
1441 _selected_hack_number = which;
1446 widget_deleter (GtkWidget *widget, gpointer data)
1448 /* #### Well, I want to destroy these widgets, but if I do that, they get
1449 referenced again, and eventually I get a SEGV. So instead of
1450 destroying them, I'll just hide them, and leak a bunch of memory
1451 every time the disk file changes. Go go go Gtk!
1453 #### Ok, that's a lie, I get a crash even if I just hide the widget
1454 and don't ever delete it. Fuck!
1457 gtk_widget_destroy (widget);
1459 gtk_widget_hide (widget);
1465 maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair)
1468 saver_preferences *p = pair->a;
1470 static Bool reentrant_lock = False;
1471 if (reentrant_lock) return 0;
1472 reentrant_lock = True;
1474 if (init_file_changed_p (p))
1476 const char *f = init_file_name();
1481 if (!f || !*f) return 0;
1482 b = (char *) malloc (strlen(f) + 1024);
1485 "file \"%s\" has changed, reloading.\n",
1487 warning_dialog (widget, b, 100);
1492 which = selected_hack_number (widget);
1493 list = GTK_LIST (name_to_widget (widget, "list"));
1494 gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL);
1495 populate_hack_list (widget, pair);
1496 gtk_list_select_item (list, which);
1497 populate_prefs_page (widget, pair);
1498 populate_demo_window (widget, which, pair);
1499 ensure_selected_item_visible (GTK_WIDGET (list));
1504 reentrant_lock = False;
1510 /* The main demo-mode command loop.
1515 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1516 XrmRepresentation *type, XrmValue *value, XPointer closure)
1519 for (i = 0; quarks[i]; i++)
1521 if (bindings[i] == XrmBindTightly)
1522 fprintf (stderr, (i == 0 ? "" : "."));
1523 else if (bindings[i] == XrmBindLoosely)
1524 fprintf (stderr, "*");
1526 fprintf (stderr, " ??? ");
1527 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1530 fprintf (stderr, ": %s\n", (char *) value->addr);
1538 the_network_is_not_the_computer (GtkWidget *parent)
1540 Display *dpy = gdk_display;
1541 char *rversion, *ruser, *rhost;
1542 char *luser, *lhost;
1544 struct passwd *p = getpwuid (getuid ());
1545 const char *d = DisplayString (dpy);
1547 # if defined(HAVE_UNAME)
1549 if (uname (&uts) < 0)
1550 lhost = "<UNKNOWN>";
1552 lhost = uts.nodename;
1554 strcpy (lhost, getenv("SYS$NODE"));
1555 # else /* !HAVE_UNAME && !VMS */
1556 strcat (lhost, "<UNKNOWN>");
1557 # endif /* !HAVE_UNAME && !VMS */
1559 if (p && p->pw_name)
1564 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
1566 /* Make a buffer that's big enough for a number of copies of all the
1567 strings, plus some. */
1568 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
1569 (ruser ? strlen(ruser) : 0) +
1570 (rhost ? strlen(rhost) : 0) +
1577 if (!rversion || !*rversion)
1581 "The XScreenSaver daemon doesn't seem to be running\n"
1582 "on display \"%s\". You can launch it by selecting\n"
1583 "`Restart Daemon' from the File menu, or by typing\n"
1584 "\"xscreensaver &\" in a shell.",
1587 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
1589 /* Warn that the two processes are running as different users.
1593 "%s is running as user \"%s\" on host \"%s\".\n"
1594 "But the xscreensaver managing display \"%s\"\n"
1595 "is running as user \"%s\" on host \"%s\".\n"
1597 "Since they are different users, they won't be reading/writing\n"
1598 "the same ~/.xscreensaver file, so %s isn't\n"
1599 "going to work right.\n"
1601 "Either re-run %s as \"%s\", or re-run\n"
1602 "xscreensaver as \"%s\" (which you can do by\n"
1603 "selecting `Restart Daemon' from the File menu.)\n",
1604 progname, luser, lhost,
1606 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1608 progname, (ruser ? ruser : "???"),
1611 else if (rhost && *rhost && !!strcmp (rhost, lhost))
1613 /* Warn that the two processes are running on different hosts.
1617 "%s is running as user \"%s\" on host \"%s\".\n"
1618 "But the xscreensaver managing display \"%s\"\n"
1619 "is running as user \"%s\" on host \"%s\".\n"
1621 "If those two machines don't share a file system (that is,\n"
1622 "if they don't see the same ~%s/.xscreensaver file) then\n"
1623 "%s won't work right.\n"
1625 "You can restart the daemon on \"%s\" as \"%s\" by\n"
1626 "selecting `Restart Daemon' from the File menu.)",
1627 progname, luser, lhost,
1629 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1634 else if (!!strcmp (rversion, short_version))
1636 /* Warn that the version numbers don't match.
1640 "This is %s version %s.\n"
1641 "But the xscreensaver managing display \"%s\"\n"
1642 "is version %s. This could cause problems.",
1643 progname, short_version,
1650 warning_dialog (parent, msg, 1);
1656 /* We use this error handler so that X errors are preceeded by the name
1657 of the program that generated them.
1660 demo_ehandler (Display *dpy, XErrorEvent *error)
1662 fprintf (stderr, "\nX error in %s:\n", progname);
1663 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
1666 fprintf (stderr, " (nonfatal.)\n");
1671 /* We use this error handler so that Gtk/Gdk errors are preceeded by the name
1672 of the program that generated them; and also that we can ignore one
1673 particular bogus error message that Gdk madly spews.
1676 g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1677 const gchar *message, gpointer user_data)
1679 /* Ignore the message "Got event for unknown window: 0x...".
1680 Apparently some events are coming in for the xscreensaver window
1681 (presumably reply events related to the ClientMessage) and Gdk
1682 feels the need to complain about them. So, just suppress any
1683 messages that look like that one.
1685 if (strstr (message, "unknown window"))
1688 fprintf (stderr, "%s: %s-%s: %s%s", blurb(), log_domain,
1689 (log_level == G_LOG_LEVEL_ERROR ? "error" :
1690 log_level == G_LOG_LEVEL_CRITICAL ? "critical" :
1691 log_level == G_LOG_LEVEL_WARNING ? "warning" :
1692 log_level == G_LOG_LEVEL_MESSAGE ? "message" :
1693 log_level == G_LOG_LEVEL_INFO ? "info" :
1694 log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"),
1696 ((!*message || message[strlen(message)-1] != '\n')
1701 static char *defaults[] = {
1702 #include "XScreenSaver_ad.h"
1707 main (int argc, char **argv)
1710 prefs_pair Pair, *pair;
1711 saver_preferences P, P2, *p, *p2;
1715 Widget toplevel_shell;
1716 GtkWidget *gtk_window;
1717 char *real_progname = argv[0];
1720 s = strrchr (real_progname, '/');
1721 if (s) real_progname = s+1;
1728 memset (p, 0, sizeof (*p));
1729 memset (p2, 0, sizeof (*p2));
1731 global_prefs_pair = pair; /* I hate C so much... */
1733 progname = real_progname;
1735 short_version = (char *) malloc (5);
1736 memcpy (short_version, screensaver_id + 17, 4);
1737 short_version [4] = 0;
1740 /* Register our error message logger for every ``log domain'' known.
1741 There's no way to do this globally, so I grepped the Gtk/Gdk sources
1742 for all of the domains that seem to be in use.
1745 const char * const domains[] = { "Gtk", "Gdk", "GLib", "GModule",
1746 "GThread", "Gnome", "GnomeUI", 0 };
1747 for (i = 0; domains[i]; i++)
1748 g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0);
1751 /* This is gross, but Gtk understands --display and not -display...
1753 for (i = 1; i < argc; i++)
1754 if (argv[i][0] && argv[i][1] &&
1755 !strncmp(argv[i], "-display", strlen(argv[i])))
1756 argv[i] = "--display";
1758 /* Let Gtk open the X connection, then initialize Xt to use that
1759 same connection. Doctor Frankenstein would be proud. */
1760 gtk_init (&argc, &argv);
1763 /* We must read exactly the same resources as xscreensaver.
1764 That means we must have both the same progclass *and* progname,
1765 at least as far as the resource database is concerned. So,
1766 put "xscreensaver" in argv[0] while initializing Xt.
1768 argv[0] = "xscreensaver";
1772 /* Teach Xt to use the Display that Gtk/Gdk have already opened.
1774 XtToolkitInitialize ();
1775 app = XtCreateApplicationContext ();
1777 XtAppSetFallbackResources (app, defaults);
1778 XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv);
1779 toplevel_shell = XtAppCreateShell (progname, progclass,
1780 applicationShellWidgetClass,
1783 dpy = XtDisplay (toplevel_shell);
1784 db = XtDatabase (dpy);
1785 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
1786 XSetErrorHandler (demo_ehandler);
1789 /* After doing Xt-style command-line processing, complain about any
1790 unrecognized command-line arguments.
1792 for (i = 1; i < argc; i++)
1795 if (s[0] == '-' && s[1] == '-')
1797 if (!strcmp (s, "-prefs"))
1801 fprintf (stderr, "%s: unknown option: %s\n", real_progname, argv[i]);
1802 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n",
1808 /* Load the init file, which may end up consulting the X resource database
1809 and the site-wide app-defaults file. Note that at this point, it's
1810 important that `progname' be "xscreensaver", rather than whatever
1817 /* Now that Xt has been initialized, and the resources have been read,
1818 we can set our `progname' variable to something more in line with
1821 progname = real_progname;
1825 /* Print out all the resources we read. */
1827 XrmName name = { 0 };
1828 XrmClass class = { 0 };
1830 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1836 /* Intern the atoms that xscreensaver_command() needs.
1838 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1839 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
1840 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
1841 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
1842 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
1843 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
1844 XA_SELECT = XInternAtom (dpy, "SELECT", False);
1845 XA_DEMO = XInternAtom (dpy, "DEMO", False);
1846 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
1847 XA_BLANK = XInternAtom (dpy, "BLANK", False);
1848 XA_LOCK = XInternAtom (dpy, "LOCK", False);
1849 XA_EXIT = XInternAtom (dpy, "EXIT", False);
1850 XA_RESTART = XInternAtom (dpy, "RESTART", False);
1853 /* Create the window and all its widgets.
1855 gtk_window = create_xscreensaver_demo ();
1857 /* Set the window's title. */
1860 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1861 char *s1, *s2, *s3, *s4;
1862 s1 = (char *) strchr(v, ' '); s1++;
1863 s2 = (char *) strchr(s1, ' ');
1864 s3 = (char *) strchr(v, '('); s3++;
1865 s4 = (char *) strchr(s3, ')');
1868 sprintf (title, "%.50s %.50s, %.50s", progclass, s1, s3);
1869 gtk_window_set_title (GTK_WINDOW (gtk_window), title);
1873 /* Various other widget initializations...
1875 gtk_signal_connect (GTK_OBJECT (gtk_window), "delete_event",
1876 GTK_SIGNAL_FUNC (wm_close_cb), NULL);
1878 populate_hack_list (gtk_window, pair);
1879 populate_prefs_page (gtk_window, pair);
1880 sensitize_demo_widgets (gtk_window, False);
1881 fix_text_entry_sizes (gtk_window);
1882 scroll_to_current_hack (gtk_window, pair);
1883 gtk_widget_show (gtk_window);
1885 /* The next three calls must come after gtk_widget_show(). */
1886 pixmapify_buttons (gtk_window);
1887 eschew_gtk_lossage (gtk_window);
1888 ensure_selected_item_visible (GTK_WIDGET(name_to_widget(gtk_window,"list")));
1890 /* Handle the -prefs command-line argument. */
1893 GtkNotebook *notebook =
1894 GTK_NOTEBOOK (name_to_widget (gtk_window, "notebook"));
1895 gtk_notebook_set_page (notebook, 1);
1898 /* Issue any warnings about the running xscreensaver daemon. */
1899 the_network_is_not_the_computer (gtk_window);
1901 /* Run the Gtk event loop, and not the Xt event loop. This means that
1902 if there were Xt timers or fds registered, they would never get serviced,
1903 and if there were any Xt widgets, they would never have events delivered.
1904 Fortunately, we're using Gtk for all of the UI, and only initialized
1905 Xt so that we could process the command line and use the X resource
1912 #endif /* HAVE_GTK -- whole file */