1 /* demo-Gtk.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
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);
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 (ratio_t < (adj->value / adj->upper) ||
190 ratio_b > ((adj->value + adj->page_size) / adj->upper))
193 int slop = parent_h * 0.75; /* how much to overshoot by */
195 if (ratio_t < (adj->value / adj->upper))
197 double ratio_w = ((double) parent_h) / ((double) children_h);
198 double ratio_l = (ratio_b - ratio_t);
199 target = ((ratio_t - ratio_w + ratio_l) * adj->upper);
202 else /* if (ratio_b > ((adj->value + adj->page_size) / adj->upper))*/
204 target = ratio_t * adj->upper;
208 if (target > adj->upper - adj->page_size)
209 target = adj->upper - adj->page_size;
213 gtk_adjustment_set_value (adj, target);
219 warning_dialog_dismiss_cb (GtkButton *button, gpointer user_data)
221 GtkWidget *shell = GTK_WIDGET (user_data);
222 while (shell->parent)
223 shell = shell->parent;
224 gtk_widget_destroy (GTK_WIDGET (shell));
229 warning_dialog (GtkWidget *parent, const char *message, int center)
231 char *msg = strdup (message);
234 GtkWidget *dialog = gtk_dialog_new ();
235 GtkWidget *label = 0;
239 while (parent->parent)
240 parent = parent->parent;
246 char *s = strchr (head, '\n');
249 sprintf (name, "label%d", i++);
253 label = gtk_label_new (head);
254 sprintf (buf, "warning_dialog.%s.font", name);
255 GTK_WIDGET (label)->style = gtk_style_copy (GTK_WIDGET (label)->style);
256 GTK_WIDGET (label)->style->font =
257 gdk_font_load (get_string_resource (buf, "Dialog.Label.Font"));
259 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
260 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
261 label, TRUE, TRUE, 0);
262 gtk_widget_show (label);
273 label = gtk_label_new ("");
274 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
275 label, TRUE, TRUE, 0);
276 gtk_widget_show (label);
278 label = gtk_hbutton_box_new ();
279 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
280 label, TRUE, TRUE, 0);
282 ok = gtk_button_new_with_label (
283 get_string_resource ("warning_dialog.ok.label",
284 "warning_dialog.Button.Label"));
285 gtk_container_add (GTK_CONTAINER (label), ok);
287 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
288 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
289 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
290 gtk_widget_show (ok);
291 gtk_widget_show (label);
292 gtk_widget_show (dialog);
293 /* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
295 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
296 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
298 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
299 GTK_WIDGET (parent)->window);
301 gdk_window_show (GTK_WIDGET (dialog)->window);
302 gdk_window_raise (GTK_WIDGET (dialog)->window);
309 run_cmd (GtkWidget *widget, Atom command, int arg)
314 apply_changes_and_save (widget);
315 status = xscreensaver_command (gdk_display, command, arg, False, &err);
320 sprintf (buf, "Error:\n\n%s", err);
322 strcpy (buf, "Unknown error!");
323 warning_dialog (widget, buf, 100);
330 run_hack (GtkWidget *widget, int which, Bool report_errors_p)
332 if (which < 0) return;
333 apply_changes_and_save (widget);
335 run_cmd (widget, XA_ACTIVATE, 0);
339 xscreensaver_command (gdk_display, XA_DEMO, which + 1, False, &s);
350 exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
352 apply_changes_and_save (GTK_WIDGET (menuitem));
357 wm_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
359 apply_changes_and_save (widget);
365 cut_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
368 warning_dialog (GTK_WIDGET (menuitem),
370 "cut unimplemented\n", 1);
375 copy_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
378 warning_dialog (GTK_WIDGET (menuitem),
380 "copy unimplemented\n", 1);
385 paste_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
388 warning_dialog (GTK_WIDGET (menuitem),
390 "paste unimplemented\n", 1);
395 about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
398 char *s = strdup (screensaver_id + 4);
401 s2 = strchr (s, ',');
405 sprintf (buf, "%s\n%s\n\n"
406 "For updates, check http://www.jwz.org/xscreensaver/",
410 warning_dialog (GTK_WIDGET (menuitem), buf, 100);
415 doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
417 /* prefs_pair *pair = (prefs_pair *) client_data; */
418 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
420 saver_preferences *p = pair->a;
423 if (!p->help_url || !*p->help_url)
425 warning_dialog (GTK_WIDGET (menuitem),
427 "No Help URL has been specified.\n", 100);
431 help_command = (char *) malloc (strlen (p->load_url_command) +
432 (strlen (p->help_url) * 2) + 20);
433 strcpy (help_command, "( ");
434 sprintf (help_command + strlen(help_command),
435 p->load_url_command, p->help_url, p->help_url);
436 strcat (help_command, " ) &");
437 system (help_command);
443 activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
445 run_cmd (GTK_WIDGET (menuitem), XA_ACTIVATE, 0);
450 lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
452 run_cmd (GTK_WIDGET (menuitem), XA_LOCK, 0);
457 kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
459 run_cmd (GTK_WIDGET (menuitem), XA_EXIT, 0);
464 restart_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
467 run_cmd (GTK_WIDGET (menuitem), XA_RESTART, 0);
469 apply_changes_and_save (GTK_WIDGET (menuitem));
470 xscreensaver_command (gdk_display, XA_EXIT, 0, False, NULL);
472 system ("xscreensaver -nosplash &");
477 static int _selected_hack_number = -1;
480 selected_hack_number (GtkWidget *toplevel)
483 GtkViewport *vp = GTK_VIEWPORT (name_to_widget (toplevel, "viewport"));
484 GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
485 GList *slist = list_widget->selection;
486 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
487 int which = (selected
488 ? gtk_list_child_position (list_widget, GTK_WIDGET (selected))
492 return _selected_hack_number;
498 demo_write_init_file (GtkWidget *widget, saver_preferences *p)
500 if (!write_init_file (p, short_version, False))
504 const char *f = init_file_name();
506 warning_dialog (widget,
507 "Error:\n\nCouldn't determine init file name!\n",
511 char *b = (char *) malloc (strlen(f) + 1024);
512 sprintf (b, "Error:\n\nCouldn't write %s\n", f);
513 warning_dialog (widget, b, 100);
522 apply_changes_and_save (GtkWidget *widget)
524 /* prefs_pair *pair = (prefs_pair *) client_data; */
525 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
526 saver_preferences *p = pair->a;
527 GtkList *list_widget =
528 GTK_LIST (name_to_widget (widget, "list"));
529 int which = selected_hack_number (widget);
531 GtkEntry *cmd = GTK_ENTRY (name_to_widget (widget, "cmd_text"));
532 GtkToggleButton *enabled =
533 GTK_TOGGLE_BUTTON (name_to_widget (widget, "enabled"));
534 GtkCombo *vis = GTK_COMBO (name_to_widget (widget, "visual_combo"));
536 Bool enabled_p = gtk_toggle_button_get_active (enabled);
537 const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
538 const char *command = gtk_entry_get_text (cmd);
543 if (which < 0) return -1;
545 /* Sanity-check and canonicalize whatever the user typed into the combo box.
547 if (!strcasecmp (visual, "")) visual = "";
548 else if (!strcasecmp (visual, "any")) visual = "";
549 else if (!strcasecmp (visual, "default")) visual = "Default";
550 else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
551 else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
552 else if (!strcasecmp (visual, "best")) visual = "Best";
553 else if (!strcasecmp (visual, "mono")) visual = "Mono";
554 else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
555 else if (!strcasecmp (visual, "gray")) visual = "Gray";
556 else if (!strcasecmp (visual, "grey")) visual = "Gray";
557 else if (!strcasecmp (visual, "color")) visual = "Color";
558 else if (!strcasecmp (visual, "gl")) visual = "GL";
559 else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
560 else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
561 else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
562 else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
563 else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
564 else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
565 else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
566 else if (1 == sscanf (visual, " %ld %c", &id, &c)) ;
567 else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
570 gdk_beep (); /* unparsable */
572 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");
575 ensure_selected_item_visible (GTK_WIDGET (list_widget));
577 if (!p->screenhacks[which]->visual)
578 p->screenhacks[which]->visual = strdup ("");
579 if (!p->screenhacks[which]->command)
580 p->screenhacks[which]->command = strdup ("");
582 if (p->screenhacks[which]->enabled_p != enabled_p ||
583 !!strcasecmp (p->screenhacks[which]->visual, visual) ||
584 !!strcasecmp (p->screenhacks[which]->command, command))
586 /* Something was changed -- store results into the struct,
589 free (p->screenhacks[which]->visual);
590 free (p->screenhacks[which]->command);
591 p->screenhacks[which]->visual = strdup (visual);
592 p->screenhacks[which]->command = strdup (command);
593 p->screenhacks[which]->enabled_p = enabled_p;
595 return demo_write_init_file (widget, p);
598 /* No changes made */
603 run_this_cb (GtkButton *button, gpointer user_data)
605 int which = selected_hack_number (GTK_WIDGET (button));
606 if (which < 0) return;
607 if (0 == apply_changes_and_save (GTK_WIDGET (button)))
608 run_hack (GTK_WIDGET (button), which, True);
613 manual_cb (GtkButton *button, gpointer user_data)
615 /* prefs_pair *pair = (prefs_pair *) client_data; */
616 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
617 saver_preferences *p = pair->a;
618 GtkList *list_widget =
619 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
620 int which = selected_hack_number (GTK_WIDGET (button));
621 char *name, *name2, *cmd, *s;
622 if (which < 0) return;
623 apply_changes_and_save (GTK_WIDGET (button));
624 ensure_selected_item_visible (GTK_WIDGET (list_widget));
626 name = strdup (p->screenhacks[which]->command);
628 while (isspace (*name2)) name2++;
630 while (*s && !isspace (*s)) s++;
632 s = strrchr (name2, '/');
635 cmd = get_string_resource ("manualCommand", "ManualCommand");
638 char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
640 sprintf (cmd2 + strlen (cmd2),
642 name2, name2, name2, name2);
643 strcat (cmd2, " ) &");
649 warning_dialog (GTK_WIDGET (button),
650 "Error:\n\nno `manualCommand' resource set.",
659 run_next_cb (GtkButton *button, gpointer user_data)
661 /* prefs_pair *pair = (prefs_pair *) client_data; */
662 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
663 saver_preferences *p = pair->a;
665 GtkList *list_widget =
666 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
667 int which = selected_hack_number (GTK_WIDGET (button));
674 if (which >= p->screenhacks_count)
677 apply_changes_and_save (GTK_WIDGET (button));
678 gtk_list_select_item (GTK_LIST (list_widget), which);
679 ensure_selected_item_visible (GTK_WIDGET (list_widget));
680 populate_demo_window (GTK_WIDGET (button), which, pair);
681 run_hack (GTK_WIDGET (button), which, False);
686 run_prev_cb (GtkButton *button, gpointer user_data)
688 /* prefs_pair *pair = (prefs_pair *) client_data; */
689 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
690 saver_preferences *p = pair->a;
692 GtkList *list_widget =
693 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
694 int which = selected_hack_number (GTK_WIDGET (button));
697 which = p->screenhacks_count - 1;
702 which = p->screenhacks_count - 1;
704 apply_changes_and_save (GTK_WIDGET (button));
705 gtk_list_select_item (GTK_LIST (list_widget), which);
706 ensure_selected_item_visible (GTK_WIDGET (list_widget));
707 populate_demo_window (GTK_WIDGET (button), which, pair);
708 run_hack (GTK_WIDGET (button), which, False);
712 /* Helper for the text fields that contain time specifications:
713 this parses the text, and does error checking.
716 hack_time_text (const char *line, Time *store, Bool sec_p)
721 value = parse_time ((char *) line, sec_p, True);
722 value *= 1000; /* Time measures in microseconds */
732 prefs_ok_cb (GtkButton *button, gpointer user_data)
734 /* prefs_pair *pair = (prefs_pair *) client_data; */
735 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
737 saver_preferences *p = pair->a;
738 saver_preferences *p2 = pair->b;
739 Bool changed = False;
741 # define SECONDS(field, name) \
742 hack_time_text (gtk_entry_get_text (\
743 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
747 # define MINUTES(field, name) \
748 hack_time_text (gtk_entry_get_text (\
749 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
753 # define INTEGER(field, name) do { \
754 char *line = gtk_entry_get_text (\
755 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
756 unsigned int value; \
760 else if (sscanf (line, "%u%c", &value, &c) != 1) \
766 # define CHECKBOX(field, name) \
767 field = gtk_toggle_button_get_active (\
768 GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET(button), (name))))
770 MINUTES (&p2->timeout, "timeout_text");
771 MINUTES (&p2->cycle, "cycle_text");
772 SECONDS (&p2->fade_seconds, "fade_text");
773 INTEGER (&p2->fade_ticks, "ticks_text");
774 MINUTES (&p2->lock_timeout, "lock_text");
775 SECONDS (&p2->passwd_timeout, "pass_text");
776 CHECKBOX (p2->verbose_p, "verbose_button");
777 CHECKBOX (p2->install_cmap_p, "install_button");
778 CHECKBOX (p2->fade_p, "fade_button");
779 CHECKBOX (p2->unfade_p, "unfade_button");
780 CHECKBOX (p2->lock_p, "lock_button");
787 # define COPY(field) \
788 if (p->field != p2->field) changed = True; \
794 COPY(passwd_timeout);
798 COPY(install_cmap_p);
804 populate_prefs_page (GTK_WIDGET (button), pair);
807 demo_write_init_file (GTK_WIDGET (button), p);
812 prefs_cancel_cb (GtkButton *button, gpointer user_data)
814 /* prefs_pair *pair = (prefs_pair *) client_data; */
815 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
818 populate_prefs_page (GTK_WIDGET (button), pair);
823 list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
824 gpointer client_data)
826 if (event->type == GDK_2BUTTON_PRESS)
828 GtkList *list = GTK_LIST (name_to_widget (button, "list"));
829 int which = gtk_list_child_position (list, GTK_WIDGET (button));
832 run_hack (GTK_WIDGET (button), which, True);
840 list_select_cb (GtkList *list, GtkWidget *child)
842 /* prefs_pair *pair = (prefs_pair *) client_data; */
843 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
845 int which = gtk_list_child_position (list, GTK_WIDGET (child));
846 apply_changes_and_save (GTK_WIDGET (list));
847 populate_demo_window (GTK_WIDGET (list), which, pair);
851 list_unselect_cb (GtkList *list, GtkWidget *child)
853 /* prefs_pair *pair = (prefs_pair *) client_data; */
854 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
856 apply_changes_and_save (GTK_WIDGET (list));
857 populate_demo_window (GTK_WIDGET (list), -1, pair);
861 /* Populating the various widgets
865 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
868 format_time (char *buf, Time time)
871 unsigned int h = 0, m = 0;
882 sprintf (buf, "%u:%02u:%02u", h, m, s);
887 make_pretty_name (const char *shell_command)
889 char *s = strdup (shell_command);
893 for (s2 = s; *s2; s2++) /* truncate at first whitespace */
900 s2 = strrchr (s, '/'); /* if pathname, take last component */
908 if (strlen (s) > 50) /* 51 is hereby defined as "unreasonable" */
911 sprintf (res_name, "hacks.%s.name", s); /* resource? */
912 s2 = get_string_resource (res_name, res_name);
916 for (s2 = s; *s2; s2++) /* if it has any capitals, return it */
917 if (*s2 >= 'A' && *s2 <= 'Z')
920 if (s[0] >= 'a' && s[0] <= 'z') /* else cap it */
922 if (s[0] == 'X' && s[1] >= 'a' && s[1] <= 'z') /* (magic leading X) */
928 /* Finds the number of the last hack to run, and makes that item be
932 scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
936 unsigned long nitems, bytesafter;
938 Display *dpy = gdk_display;
942 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
943 XA_SCREENSAVER_STATUS,
944 0, 3, False, XA_INTEGER,
945 &type, &format, &nitems, &bytesafter,
946 (unsigned char **) &data)
948 && type == XA_INTEGER
951 which = (int) data[2] - 1;
953 if (data) free (data);
958 list = GTK_LIST (name_to_widget (toplevel, "list"));
959 apply_changes_and_save (toplevel);
960 gtk_list_select_item (list, which);
961 ensure_selected_item_visible (GTK_WIDGET (list));
962 populate_demo_window (toplevel, which, pair);
968 populate_hack_list (GtkWidget *toplevel, prefs_pair *pair)
970 saver_preferences *p = pair->a;
971 GtkList *list = GTK_LIST (name_to_widget (toplevel, "list"));
972 screenhack **hacks = p->screenhacks;
975 for (h = hacks; *h; h++)
978 char *pretty_name = (h[0]->name
979 ? strdup (h[0]->name)
980 : make_pretty_name (h[0]->command));
982 line = gtk_list_item_new_with_label (pretty_name);
985 gtk_container_add (GTK_CONTAINER (list), line);
986 gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
987 GTK_SIGNAL_FUNC (list_doubleclick_cb),
990 GTK_WIDGET (GTK_BIN(line)->child)->style =
991 gtk_style_copy (GTK_WIDGET (text_line)->style);
993 gtk_widget_show (line);
996 gtk_signal_connect (GTK_OBJECT (list), "select_child",
997 GTK_SIGNAL_FUNC (list_select_cb),
999 gtk_signal_connect (GTK_OBJECT (list), "unselect_child",
1000 GTK_SIGNAL_FUNC (list_unselect_cb),
1006 populate_prefs_page (GtkWidget *top, prefs_pair *pair)
1008 saver_preferences *p = pair->a;
1011 format_time (s, p->timeout);
1012 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "timeout_text")), s);
1013 format_time (s, p->cycle);
1014 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "cycle_text")), s);
1015 format_time (s, p->lock_timeout);
1016 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "lock_text")), s);
1017 format_time (s, p->passwd_timeout);
1018 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "pass_text")), s);
1019 format_time (s, p->fade_seconds);
1020 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "fade_text")), s);
1021 sprintf (s, "%u", p->fade_ticks);
1022 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "ticks_text")), s);
1024 gtk_toggle_button_set_active (
1025 GTK_TOGGLE_BUTTON (name_to_widget (top, "verbose_button")),
1027 gtk_toggle_button_set_active (
1028 GTK_TOGGLE_BUTTON (name_to_widget (top, "install_button")),
1030 gtk_toggle_button_set_active (
1031 GTK_TOGGLE_BUTTON (name_to_widget (top, "fade_button")),
1033 gtk_toggle_button_set_active (
1034 GTK_TOGGLE_BUTTON (name_to_widget (top, "unfade_button")),
1036 gtk_toggle_button_set_active (
1037 GTK_TOGGLE_BUTTON (name_to_widget (top, "lock_button")),
1042 Bool found_any_writable_cells = False;
1043 Display *dpy = gdk_display;
1044 int nscreens = ScreenCount(dpy);
1046 for (i = 0; i < nscreens; i++)
1048 Screen *s = ScreenOfDisplay (dpy, i);
1049 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1051 found_any_writable_cells = True;
1056 gtk_widget_set_sensitive (
1057 GTK_WIDGET (name_to_widget (top, "fade_label")),
1058 found_any_writable_cells);
1059 gtk_widget_set_sensitive (
1060 GTK_WIDGET (name_to_widget (top, "ticks_label")),
1061 found_any_writable_cells);
1062 gtk_widget_set_sensitive (
1063 GTK_WIDGET (name_to_widget (top, "fade_text")),
1064 found_any_writable_cells);
1065 gtk_widget_set_sensitive (
1066 GTK_WIDGET (name_to_widget (top, "ticks_text")),
1067 found_any_writable_cells);
1068 gtk_widget_set_sensitive (
1069 GTK_WIDGET (name_to_widget (top, "install_button")),
1070 found_any_writable_cells);
1071 gtk_widget_set_sensitive (
1072 GTK_WIDGET (name_to_widget (top, "fade_button")),
1073 found_any_writable_cells);
1074 gtk_widget_set_sensitive (
1075 GTK_WIDGET (name_to_widget (top, "unfade_button")),
1076 found_any_writable_cells);
1083 sensitize_demo_widgets (GtkWidget *toplevel, Bool sensitive_p)
1085 const char *names[] = { "cmd_label", "cmd_text", "enabled",
1086 "visual", "visual_combo",
1089 for (i = 0; i < countof(names); i++)
1091 GtkWidget *w = name_to_widget (toplevel, names[i]);
1092 gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
1095 /* I don't know how to handle these yet... */
1097 const char *names2[] = { "cut_menu", "copy_menu", "paste_menu" };
1098 for (i = 0; i < countof(names2); i++)
1100 GtkWidget *w = name_to_widget (toplevel, names2[i]);
1101 gtk_widget_set_sensitive (GTK_WIDGET(w), False);
1107 /* Even though we've given these text fields a maximum number of characters,
1108 their default size is still about 30 characters wide -- so measure out
1109 a string in their font, and resize them to just fit that.
1112 fix_text_entry_sizes (GtkWidget *toplevel)
1114 const char *names[] = { "timeout_text", "cycle_text", "fade_text",
1115 "ticks_text", "lock_text", "pass_text" };
1120 for (i = 0; i < countof(names); i++)
1122 w = GTK_WIDGET (name_to_widget (toplevel, names[i]));
1124 width = gdk_text_width (w->style->font, "00:00:00_", 9);
1125 gtk_widget_set_usize (w, width, -2);
1128 /* Now fix the size of the combo box.
1130 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "visual_combo"));
1131 w = GTK_COMBO (w)->entry;
1132 width = gdk_text_width (w->style->font, "PseudoColor___", 14);
1133 gtk_widget_set_usize (w, width, -2);
1136 /* Now fix the size of the list.
1138 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "list"));
1139 width = gdk_text_width (w->style->font, "nnnnnnnnnnnnnnnnnnnnnn", 22);
1140 gtk_widget_set_usize (w, width, -2);
1147 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...)
1150 static char *up_arrow_xpm[] = {
1173 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1174 the end of the array (Gtk 1.2.5.) */
1175 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1176 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1179 static char *down_arrow_xpm[] = {
1201 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1202 the end of the array (Gtk 1.2.5.) */
1203 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1204 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1208 pixmapify_buttons (GtkWidget *toplevel)
1212 GtkWidget *pixmapwid;
1216 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "next"));
1217 style = gtk_widget_get_style (w);
1219 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1220 &style->bg[GTK_STATE_NORMAL],
1221 (gchar **) down_arrow_xpm);
1222 pixmapwid = gtk_pixmap_new (pixmap, mask);
1223 gtk_widget_show (pixmapwid);
1224 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1225 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1227 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "prev"));
1228 style = gtk_widget_get_style (w);
1230 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1231 &style->bg[GTK_STATE_NORMAL],
1232 (gchar **) up_arrow_xpm);
1233 pixmapwid = gtk_pixmap_new (pixmap, mask);
1234 gtk_widget_show (pixmapwid);
1235 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1236 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1241 /* Work around a Gtk bug that causes label widgets to wrap text too early.
1245 you_are_not_a_unique_or_beautiful_snowflake (GtkWidget *label,
1246 GtkAllocation *allocation,
1250 GtkWidgetAuxInfo *aux_info;
1252 aux_info = gtk_object_get_data (GTK_OBJECT (label), "gtk-aux-info");
1254 aux_info->width = allocation->width;
1255 aux_info->height = -2;
1259 gtk_widget_size_request (label, &req);
1263 /* Feel the love. Thanks to Nat Friedman for finding this workaround.
1266 eschew_gtk_lossage (GtkWidget *toplevel)
1268 GtkWidgetAuxInfo *aux_info;
1269 GtkWidget *label = GTK_WIDGET (name_to_widget (toplevel, "doc"));
1271 aux_info = g_new0 (GtkWidgetAuxInfo, 1);
1272 aux_info->width = label->allocation.width;
1273 aux_info->height = -2;
1277 gtk_object_set_data (GTK_OBJECT (label), "gtk-aux-info", aux_info);
1279 gtk_signal_connect (GTK_OBJECT (label), "size_allocate",
1280 you_are_not_a_unique_or_beautiful_snowflake, NULL);
1282 gtk_widget_queue_resize (label);
1287 get_hack_blurb (screenhack *hack)
1290 char *prog_name = strdup (hack->command);
1291 char *pretty_name = (hack->name
1292 ? strdup (hack->name)
1293 : make_pretty_name (hack->command));
1294 char doc_name[255], doc_class[255];
1297 for (s = prog_name; *s && !isspace(*s); s++)
1300 s = strrchr (prog_name, '/');
1301 if (s) strcpy (prog_name, s+1);
1303 sprintf (doc_name, "hacks.%s.documentation", pretty_name);
1304 sprintf (doc_class, "hacks.%s.documentation", prog_name);
1308 doc_string = get_string_resource (doc_name, doc_class);
1311 for (s = doc_string; *s; s++)
1315 /* skip over whitespace at beginning of line */
1317 while (*s && (*s == ' ' || *s == '\t'))
1320 else if (*s == ' ' || *s == '\t')
1322 /* compress all other horizontal whitespace. */
1325 for (s2 = s; *s2 && (*s2 == ' ' || *s2 == '\t'); s2++)
1327 if (s2 > s) strcpy (s, s2);
1332 while (*s && isspace (*s)) /* Strip trailing whitespace */
1335 /* Delete whitespace at end of each line. */
1336 for (; s > doc_string; s--)
1337 if (*s == '\n' && (s[-1] == ' ' || s[-1] == '\t'))
1340 s2 > doc_string && (*s2 == ' ' || *s2 == '\t');
1344 if (s2 < s) strcpy (s2, s);
1348 /* Delete leading blank lines. */
1349 for (s = doc_string; *s == '\n'; s++)
1351 if (s > doc_string) strcpy (doc_string, s);
1355 static int doc_installed = 0;
1356 if (doc_installed == 0)
1358 if (get_boolean_resource ("hacks.documentation.isInstalled",
1359 "hacks.documentation.isInstalled"))
1365 if (doc_installed < 0)
1367 strdup ("Error:\n\n"
1368 "The documentation strings do not appear to be "
1369 "installed. This is probably because there is "
1370 "an \"XScreenSaver\" app-defaults file installed "
1371 "that is from an older version of the program. "
1372 "To fix this problem, delete that file, or "
1373 "install a current version (either will work.)");
1375 doc_string = strdup ("");
1383 populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
1385 saver_preferences *p = pair->a;
1386 screenhack *hack = (which >= 0 ? p->screenhacks[which] : 0);
1387 GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
1388 GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
1389 GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
1390 GtkToggleButton *enabled =
1391 GTK_TOGGLE_BUTTON (name_to_widget (toplevel, "enabled"));
1392 GtkCombo *vis = GTK_COMBO (name_to_widget (toplevel, "visual_combo"));
1394 char *pretty_name = (hack
1396 ? strdup (hack->name)
1397 : make_pretty_name (hack->command))
1399 char *doc_string = hack ? get_hack_blurb (hack) : 0;
1401 gtk_frame_set_label (frame, (pretty_name ? pretty_name : ""));
1402 gtk_label_set_text (doc, (doc_string ? doc_string : ""));
1403 gtk_entry_set_text (cmd, (hack ? hack->command : ""));
1404 gtk_entry_set_position (cmd, 0);
1405 gtk_toggle_button_set_active (enabled, (hack ? hack->enabled_p : False));
1406 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry),
1408 ? (hack->visual && *hack->visual
1413 gtk_container_resize_children (GTK_CONTAINER (GTK_WIDGET (doc)->parent));
1415 sensitize_demo_widgets (toplevel, (hack ? True : False));
1417 if (pretty_name) free (pretty_name);
1418 if (doc_string) free (doc_string);
1420 _selected_hack_number = which;
1426 /* The main demo-mode command loop.
1431 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1432 XrmRepresentation *type, XrmValue *value, XPointer closure)
1435 for (i = 0; quarks[i]; i++)
1437 if (bindings[i] == XrmBindTightly)
1438 fprintf (stderr, (i == 0 ? "" : "."));
1439 else if (bindings[i] == XrmBindLoosely)
1440 fprintf (stderr, "*");
1442 fprintf (stderr, " ??? ");
1443 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1446 fprintf (stderr, ": %s\n", (char *) value->addr);
1454 the_network_is_not_the_computer (GtkWidget *parent)
1456 Display *dpy = gdk_display;
1457 char *rversion, *ruser, *rhost;
1458 char *luser, *lhost;
1460 struct passwd *p = getpwuid (getuid ());
1461 const char *d = DisplayString (dpy);
1463 # if defined(HAVE_UNAME)
1465 if (uname (&uts) < 0)
1466 lhost = "<UNKNOWN>";
1468 lhost = uts.nodename;
1470 strcpy (lhost, getenv("SYS$NODE"));
1471 # else /* !HAVE_UNAME && !VMS */
1472 strcat (lhost, "<UNKNOWN>");
1473 # endif /* !HAVE_UNAME && !VMS */
1475 if (p && p->pw_name)
1480 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
1482 /* Make a buffer that's big enough for a number of copies of all the
1483 strings, plus some. */
1484 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
1485 (ruser ? strlen(ruser) : 0) +
1486 (rhost ? strlen(rhost) : 0) +
1493 if (!rversion || !*rversion)
1497 "The XScreenSaver daemon doesn't seem to be running\n"
1498 "on display \"%s\". You can launch it by selecting\n"
1499 "`Restart Daemon' from the File menu, or by typing\n"
1500 "\"xscreensaver &\" in a shell.",
1503 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
1505 /* Warn that the two processes are running as different users.
1509 "%s is running as user \"%s\" on host \"%s\".\n"
1510 "But the xscreensaver managing display \"%s\"\n"
1511 "is running as user \"%s\" on host \"%s\".\n"
1513 "Since they are different users, they won't be reading/writing\n"
1514 "the same ~/.xscreensaver file, so %s isn't\n"
1515 "going to work right.\n"
1517 "Either re-run %s as \"%s\", or re-run\n"
1518 "xscreensaver as \"%s\" (which you can do by\n"
1519 "selecting `Restart Daemon' from the File menu.)\n",
1520 progname, luser, lhost,
1522 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1524 progname, (ruser ? ruser : "???"),
1527 else if (rhost && *rhost && !!strcmp (rhost, lhost))
1529 /* Warn that the two processes are running on different hosts.
1533 "%s is running as user \"%s\" on host \"%s\".\n"
1534 "But the xscreensaver managing display \"%s\"\n"
1535 "is running as user \"%s\" on host \"%s\".\n"
1537 "If those two machines don't share a file system (that is,\n"
1538 "if they don't see the same ~%s/.xscreensaver file) then\n"
1539 "%s won't work right.\n"
1541 "You can restart the daemon on \"%s\" as \"%s\" by\n"
1542 "selecting `Restart Daemon' from the File menu.)",
1543 progname, luser, lhost,
1545 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1550 else if (!!strcmp (rversion, short_version))
1552 /* Warn that the version numbers don't match.
1556 "This is %s version %s.\n"
1557 "But the xscreensaver managing display \"%s\"\n"
1558 "is version %s. This could cause problems.",
1559 progname, short_version,
1566 warning_dialog (parent, msg, 1);
1572 /* We use this error handler so that X errors are preceeded by the name
1573 of the program that generated them.
1576 demo_ehandler (Display *dpy, XErrorEvent *error)
1578 fprintf (stderr, "\nX error in %s:\n", progname);
1579 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
1582 fprintf (stderr, " (nonfatal.)\n");
1587 /* We use this error handler so that Gtk/Gdk errors are preceeded by the name
1588 of the program that generated them; and also that we can ignore one
1589 particular bogus error message that Gdk madly spews.
1592 g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1593 const gchar *message, gpointer user_data)
1595 /* Ignore the message "Got event for unknown window: 0x...".
1596 Apparently some events are coming in for the xscreensaver window
1597 (presumably reply events related to the ClientMessage) and Gdk
1598 feels the need to complain about them. So, just suppress any
1599 messages that look like that one.
1601 if (strstr (message, "unknown window"))
1604 fprintf (stderr, "%s: %s-%s: %s%s", blurb(), log_domain,
1605 (log_level == G_LOG_LEVEL_ERROR ? "error" :
1606 log_level == G_LOG_LEVEL_CRITICAL ? "critical" :
1607 log_level == G_LOG_LEVEL_WARNING ? "warning" :
1608 log_level == G_LOG_LEVEL_MESSAGE ? "message" :
1609 log_level == G_LOG_LEVEL_INFO ? "info" :
1610 log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"),
1612 ((!*message || message[strlen(message)-1] != '\n')
1617 static char *defaults[] = {
1618 #include "XScreenSaver_ad.h"
1623 main (int argc, char **argv)
1626 prefs_pair Pair, *pair;
1627 saver_preferences P, P2, *p, *p2;
1631 Widget toplevel_shell;
1632 GtkWidget *gtk_window;
1633 char *real_progname = argv[0];
1636 s = strrchr (real_progname, '/');
1637 if (s) real_progname = s+1;
1644 memset (p, 0, sizeof (*p));
1645 memset (p2, 0, sizeof (*p2));
1647 global_prefs_pair = pair; /* I hate C so much... */
1649 progname = real_progname;
1651 short_version = (char *) malloc (5);
1652 memcpy (short_version, screensaver_id + 17, 4);
1653 short_version [4] = 0;
1656 /* Register our error message logger for every ``log domain'' known.
1657 There's no way to do this globally, so I grepped the Gtk/Gdk sources
1658 for all of the domains that seem to be in use.
1661 const char * const domains[] = { "Gtk", "Gdk", "GLib", "GModule",
1662 "GThread", "Gnome", "GnomeUI", 0 };
1663 for (i = 0; domains[i]; i++)
1664 g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0);
1667 /* This is gross, but Gtk understands --display and not -display...
1669 for (i = 1; i < argc; i++)
1670 if (argv[i][0] && argv[i][1] &&
1671 !strncmp(argv[i], "-display", strlen(argv[i])))
1672 argv[i] = "--display";
1674 /* Let Gtk open the X connection, then initialize Xt to use that
1675 same connection. Doctor Frankenstein would be proud. */
1676 gtk_init (&argc, &argv);
1679 /* We must read exactly the same resources as xscreensaver.
1680 That means we must have both the same progclass *and* progname,
1681 at least as far as the resource database is concerned. So,
1682 put "xscreensaver" in argv[0] while initializing Xt.
1684 argv[0] = "xscreensaver";
1688 /* Teach Xt to use the Display that Gtk/Gdk have already opened.
1690 XtToolkitInitialize ();
1691 app = XtCreateApplicationContext ();
1693 XtAppSetFallbackResources (app, defaults);
1694 XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv);
1695 toplevel_shell = XtAppCreateShell (progname, progclass,
1696 applicationShellWidgetClass,
1699 dpy = XtDisplay (toplevel_shell);
1700 db = XtDatabase (dpy);
1701 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
1702 XSetErrorHandler (demo_ehandler);
1705 /* After doing Xt-style command-line processing, complain about any
1706 unrecognized command-line arguments.
1708 for (i = 1; i < argc; i++)
1711 if (s[0] == '-' && s[1] == '-')
1713 if (!strcmp (s, "-prefs"))
1717 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n",
1723 /* Load the init file, which may end up consulting the X resource database
1724 and the site-wide app-defaults file. Note that at this point, it's
1725 important that `progname' be "xscreensaver", rather than whatever
1732 /* Now that Xt has been initialized, and the resources have been read,
1733 we can set our `progname' variable to something more in line with
1736 progname = real_progname;
1740 /* Print out all the resources we read. */
1742 XrmName name = { 0 };
1743 XrmClass class = { 0 };
1745 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1751 /* Intern the atoms that xscreensaver_command() needs.
1753 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1754 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
1755 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
1756 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
1757 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
1758 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
1759 XA_SELECT = XInternAtom (dpy, "SELECT", False);
1760 XA_DEMO = XInternAtom (dpy, "DEMO", False);
1761 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
1762 XA_BLANK = XInternAtom (dpy, "BLANK", False);
1763 XA_LOCK = XInternAtom (dpy, "LOCK", False);
1764 XA_EXIT = XInternAtom (dpy, "EXIT", False);
1765 XA_RESTART = XInternAtom (dpy, "RESTART", False);
1768 /* Create the window and all its widgets.
1770 gtk_window = create_xscreensaver_demo ();
1772 /* Set the window's title. */
1775 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1776 char *s1, *s2, *s3, *s4;
1777 s1 = (char *) strchr(v, ' '); s1++;
1778 s2 = (char *) strchr(s1, ' ');
1779 s3 = (char *) strchr(v, '('); s3++;
1780 s4 = (char *) strchr(s3, ')');
1783 sprintf (title, "%.50s %.50s, %.50s", progclass, s1, s3);
1784 gtk_window_set_title (GTK_WINDOW (gtk_window), title);
1788 /* Various other widget initializations...
1790 gtk_signal_connect (GTK_OBJECT (gtk_window), "delete_event",
1791 GTK_SIGNAL_FUNC (wm_close_cb), NULL);
1793 populate_hack_list (gtk_window, pair);
1794 populate_prefs_page (gtk_window, pair);
1795 sensitize_demo_widgets (gtk_window, False);
1796 fix_text_entry_sizes (gtk_window);
1797 scroll_to_current_hack (gtk_window, pair);
1798 gtk_widget_show (gtk_window);
1800 /* The next three calls must come after gtk_widget_show(). */
1801 pixmapify_buttons (gtk_window);
1802 eschew_gtk_lossage (gtk_window);
1803 ensure_selected_item_visible (GTK_WIDGET(name_to_widget(gtk_window,"list")));
1805 /* Handle the -prefs command-line argument. */
1808 GtkNotebook *notebook =
1809 GTK_NOTEBOOK (name_to_widget (gtk_window, "notebook"));
1810 gtk_notebook_set_page (notebook, 1);
1813 /* Issue any warnings about the running xscreensaver daemon. */
1814 the_network_is_not_the_computer (gtk_window);
1816 /* Run the Gtk event loop, and not the Xt event loop. This means that
1817 if there were Xt timers or fds registered, they would never get serviced,
1818 and if there were any Xt widgets, they would never have events delivered.
1819 Fortunately, we're using Gtk for all of the UI, and only initialized
1820 Xt so that we could process the command line and use the X resource
1827 #endif /* HAVE_GTK -- whole file */