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 (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 ("OK");
283 gtk_container_add (GTK_CONTAINER (label), ok);
285 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
286 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
287 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
288 gtk_widget_show (ok);
289 gtk_widget_show (label);
290 gtk_widget_show (dialog);
291 /* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
293 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
294 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
296 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
297 GTK_WIDGET (parent)->window);
299 gdk_window_show (GTK_WIDGET (dialog)->window);
300 gdk_window_raise (GTK_WIDGET (dialog)->window);
307 run_cmd (GtkWidget *widget, Atom command, int arg)
312 apply_changes_and_save (widget);
313 status = xscreensaver_command (gdk_display, command, arg, False, &err);
318 sprintf (buf, "Error:\n\n%s", err);
320 strcpy (buf, "Unknown error!");
321 warning_dialog (widget, buf, 100);
328 run_hack (GtkWidget *widget, int which, Bool report_errors_p)
330 if (which < 0) return;
331 apply_changes_and_save (widget);
333 run_cmd (widget, XA_DEMO, which + 1);
337 xscreensaver_command (gdk_display, XA_DEMO, which + 1, False, &s);
348 exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
350 apply_changes_and_save (GTK_WIDGET (menuitem));
355 wm_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
357 apply_changes_and_save (widget);
363 cut_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
366 warning_dialog (GTK_WIDGET (menuitem),
368 "cut unimplemented\n", 1);
373 copy_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
376 warning_dialog (GTK_WIDGET (menuitem),
378 "copy unimplemented\n", 1);
383 paste_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
386 warning_dialog (GTK_WIDGET (menuitem),
388 "paste unimplemented\n", 1);
393 about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
396 char *s = strdup (screensaver_id + 4);
399 s2 = strchr (s, ',');
403 sprintf (buf, "%s\n%s\n\n"
404 "For updates, check http://www.jwz.org/xscreensaver/",
408 warning_dialog (GTK_WIDGET (menuitem), buf, 100);
413 doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
415 /* prefs_pair *pair = (prefs_pair *) client_data; */
416 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
418 saver_preferences *p = pair->a;
421 if (!p->help_url || !*p->help_url)
423 warning_dialog (GTK_WIDGET (menuitem),
425 "No Help URL has been specified.\n", 100);
429 help_command = (char *) malloc (strlen (p->load_url_command) +
430 (strlen (p->help_url) * 2) + 20);
431 strcpy (help_command, "( ");
432 sprintf (help_command + strlen(help_command),
433 p->load_url_command, p->help_url, p->help_url);
434 strcat (help_command, " ) &");
435 system (help_command);
441 activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
443 run_cmd (GTK_WIDGET (menuitem), XA_ACTIVATE, 0);
448 lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
450 run_cmd (GTK_WIDGET (menuitem), XA_LOCK, 0);
455 kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
457 run_cmd (GTK_WIDGET (menuitem), XA_EXIT, 0);
462 restart_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
465 run_cmd (GTK_WIDGET (menuitem), XA_RESTART, 0);
467 apply_changes_and_save (GTK_WIDGET (menuitem));
468 xscreensaver_command (gdk_display, XA_EXIT, 0, False, NULL);
470 system ("xscreensaver -nosplash &");
475 static int _selected_hack_number = -1;
478 selected_hack_number (GtkWidget *toplevel)
481 GtkViewport *vp = GTK_VIEWPORT (name_to_widget (toplevel, "viewport"));
482 GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
483 GList *slist = list_widget->selection;
484 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
485 int which = (selected
486 ? gtk_list_child_position (list_widget, GTK_WIDGET (selected))
490 return _selected_hack_number;
496 demo_write_init_file (GtkWidget *widget, saver_preferences *p)
498 if (!write_init_file (p, short_version, False))
502 const char *f = init_file_name();
504 warning_dialog (widget,
505 "Error:\n\nCouldn't determine init file name!\n",
509 char *b = (char *) malloc (strlen(f) + 1024);
510 sprintf (b, "Error:\n\nCouldn't write %s\n", f);
511 warning_dialog (widget, b, 100);
520 apply_changes_and_save (GtkWidget *widget)
522 /* prefs_pair *pair = (prefs_pair *) client_data; */
523 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
524 saver_preferences *p = pair->a;
525 GtkList *list_widget =
526 GTK_LIST (name_to_widget (widget, "list"));
527 int which = selected_hack_number (widget);
529 GtkEntry *cmd = GTK_ENTRY (name_to_widget (widget, "cmd_text"));
530 GtkToggleButton *enabled =
531 GTK_TOGGLE_BUTTON (name_to_widget (widget, "enabled"));
532 GtkCombo *vis = GTK_COMBO (name_to_widget (widget, "visual_combo"));
534 Bool enabled_p = gtk_toggle_button_get_active (enabled);
535 const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
536 const char *command = gtk_entry_get_text (cmd);
541 if (which < 0) return -1;
543 if (maybe_reload_init_file (widget, pair) != 0)
546 /* Sanity-check and canonicalize whatever the user typed into the combo box.
548 if (!strcasecmp (visual, "")) visual = "";
549 else if (!strcasecmp (visual, "any")) visual = "";
550 else if (!strcasecmp (visual, "default")) visual = "Default";
551 else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
552 else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
553 else if (!strcasecmp (visual, "best")) visual = "Best";
554 else if (!strcasecmp (visual, "mono")) visual = "Mono";
555 else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
556 else if (!strcasecmp (visual, "gray")) visual = "Gray";
557 else if (!strcasecmp (visual, "grey")) visual = "Gray";
558 else if (!strcasecmp (visual, "color")) visual = "Color";
559 else if (!strcasecmp (visual, "gl")) visual = "GL";
560 else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
561 else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
562 else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
563 else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
564 else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
565 else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
566 else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
567 else if (1 == sscanf (visual, " %ld %c", &id, &c)) ;
568 else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
571 gdk_beep (); /* unparsable */
573 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");
576 ensure_selected_item_visible (GTK_WIDGET (list_widget));
578 if (!p->screenhacks[which]->visual)
579 p->screenhacks[which]->visual = strdup ("");
580 if (!p->screenhacks[which]->command)
581 p->screenhacks[which]->command = strdup ("");
583 if (p->screenhacks[which]->enabled_p != enabled_p ||
584 !!strcasecmp (p->screenhacks[which]->visual, visual) ||
585 !!strcasecmp (p->screenhacks[which]->command, command))
587 /* Something was changed -- store results into the struct,
590 free (p->screenhacks[which]->visual);
591 free (p->screenhacks[which]->command);
592 p->screenhacks[which]->visual = strdup (visual);
593 p->screenhacks[which]->command = strdup (command);
594 p->screenhacks[which]->enabled_p = enabled_p;
596 return demo_write_init_file (widget, p);
599 /* No changes made */
604 run_this_cb (GtkButton *button, gpointer user_data)
606 int which = selected_hack_number (GTK_WIDGET (button));
607 if (which < 0) return;
608 if (0 == apply_changes_and_save (GTK_WIDGET (button)))
609 run_hack (GTK_WIDGET (button), which, True);
614 manual_cb (GtkButton *button, gpointer user_data)
616 /* prefs_pair *pair = (prefs_pair *) client_data; */
617 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
618 saver_preferences *p = pair->a;
619 GtkList *list_widget =
620 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
621 int which = selected_hack_number (GTK_WIDGET (button));
622 char *name, *name2, *cmd, *s;
623 if (which < 0) return;
624 apply_changes_and_save (GTK_WIDGET (button));
625 ensure_selected_item_visible (GTK_WIDGET (list_widget));
627 name = strdup (p->screenhacks[which]->command);
629 while (isspace (*name2)) name2++;
631 while (*s && !isspace (*s)) s++;
633 s = strrchr (name2, '/');
636 cmd = get_string_resource ("manualCommand", "ManualCommand");
639 char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
641 sprintf (cmd2 + strlen (cmd2),
643 name2, name2, name2, name2);
644 strcat (cmd2, " ) &");
650 warning_dialog (GTK_WIDGET (button),
651 "Error:\n\nno `manualCommand' resource set.",
660 run_next_cb (GtkButton *button, gpointer user_data)
662 /* prefs_pair *pair = (prefs_pair *) client_data; */
663 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
664 saver_preferences *p = pair->a;
666 GtkList *list_widget =
667 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
668 int which = selected_hack_number (GTK_WIDGET (button));
675 if (which >= p->screenhacks_count)
678 apply_changes_and_save (GTK_WIDGET (button));
679 gtk_list_select_item (GTK_LIST (list_widget), which);
680 ensure_selected_item_visible (GTK_WIDGET (list_widget));
681 populate_demo_window (GTK_WIDGET (button), which, pair);
682 run_hack (GTK_WIDGET (button), which, False);
687 run_prev_cb (GtkButton *button, gpointer user_data)
689 /* prefs_pair *pair = (prefs_pair *) client_data; */
690 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
691 saver_preferences *p = pair->a;
693 GtkList *list_widget =
694 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
695 int which = selected_hack_number (GTK_WIDGET (button));
698 which = p->screenhacks_count - 1;
703 which = p->screenhacks_count - 1;
705 apply_changes_and_save (GTK_WIDGET (button));
706 gtk_list_select_item (GTK_LIST (list_widget), which);
707 ensure_selected_item_visible (GTK_WIDGET (list_widget));
708 populate_demo_window (GTK_WIDGET (button), which, pair);
709 run_hack (GTK_WIDGET (button), which, False);
713 /* Helper for the text fields that contain time specifications:
714 this parses the text, and does error checking.
717 hack_time_text (const char *line, Time *store, Bool sec_p)
722 value = parse_time ((char *) line, sec_p, True);
723 value *= 1000; /* Time measures in microseconds */
733 prefs_ok_cb (GtkButton *button, gpointer user_data)
735 /* prefs_pair *pair = (prefs_pair *) client_data; */
736 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
738 saver_preferences *p = pair->a;
739 saver_preferences *p2 = pair->b;
740 Bool changed = False;
742 # define SECONDS(field, name) \
743 hack_time_text (gtk_entry_get_text (\
744 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
748 # define MINUTES(field, name) \
749 hack_time_text (gtk_entry_get_text (\
750 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
754 # define INTEGER(field, name) do { \
755 char *line = gtk_entry_get_text (\
756 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
757 unsigned int value; \
761 else if (sscanf (line, "%u%c", &value, &c) != 1) \
767 # define CHECKBOX(field, name) \
768 field = gtk_toggle_button_get_active (\
769 GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET(button), (name))))
771 MINUTES (&p2->timeout, "timeout_text");
772 MINUTES (&p2->cycle, "cycle_text");
773 SECONDS (&p2->fade_seconds, "fade_text");
774 INTEGER (&p2->fade_ticks, "ticks_text");
775 MINUTES (&p2->lock_timeout, "lock_text");
776 SECONDS (&p2->passwd_timeout, "pass_text");
777 CHECKBOX (p2->verbose_p, "verbose_button");
778 CHECKBOX (p2->install_cmap_p, "install_button");
779 CHECKBOX (p2->fade_p, "fade_button");
780 CHECKBOX (p2->unfade_p, "unfade_button");
781 CHECKBOX (p2->lock_p, "lock_button");
788 # define COPY(field) \
789 if (p->field != p2->field) changed = True; \
795 COPY(passwd_timeout);
799 COPY(install_cmap_p);
805 populate_prefs_page (GTK_WIDGET (button), pair);
808 demo_write_init_file (GTK_WIDGET (button), p);
813 prefs_cancel_cb (GtkButton *button, gpointer user_data)
815 /* prefs_pair *pair = (prefs_pair *) client_data; */
816 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
819 populate_prefs_page (GTK_WIDGET (button), pair);
824 list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
825 gpointer client_data)
827 if (event->type == GDK_2BUTTON_PRESS)
829 GtkList *list = GTK_LIST (name_to_widget (button, "list"));
830 int which = gtk_list_child_position (list, GTK_WIDGET (button));
833 run_hack (GTK_WIDGET (button), which, True);
841 list_select_cb (GtkList *list, GtkWidget *child)
843 /* prefs_pair *pair = (prefs_pair *) client_data; */
844 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
846 int which = gtk_list_child_position (list, GTK_WIDGET (child));
847 apply_changes_and_save (GTK_WIDGET (list));
848 populate_demo_window (GTK_WIDGET (list), which, pair);
852 list_unselect_cb (GtkList *list, GtkWidget *child)
854 /* prefs_pair *pair = (prefs_pair *) client_data; */
855 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
857 apply_changes_and_save (GTK_WIDGET (list));
858 populate_demo_window (GTK_WIDGET (list), -1, pair);
862 /* Populating the various widgets
866 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
869 format_time (char *buf, Time time)
872 unsigned int h = 0, m = 0;
883 sprintf (buf, "%u:%02u:%02u", h, m, s);
888 make_pretty_name (const char *shell_command)
890 char *s = strdup (shell_command);
894 for (s2 = s; *s2; s2++) /* truncate at first whitespace */
901 s2 = strrchr (s, '/'); /* if pathname, take last component */
909 if (strlen (s) > 50) /* 51 is hereby defined as "unreasonable" */
912 sprintf (res_name, "hacks.%s.name", s); /* resource? */
913 s2 = get_string_resource (res_name, res_name);
917 for (s2 = s; *s2; s2++) /* if it has any capitals, return it */
918 if (*s2 >= 'A' && *s2 <= 'Z')
921 if (s[0] >= 'a' && s[0] <= 'z') /* else cap it */
923 if (s[0] == 'X' && s[1] >= 'a' && s[1] <= 'z') /* (magic leading X) */
929 /* Finds the number of the last hack to run, and makes that item be
933 scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
937 unsigned long nitems, bytesafter;
939 Display *dpy = gdk_display;
943 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
944 XA_SCREENSAVER_STATUS,
945 0, 3, False, XA_INTEGER,
946 &type, &format, &nitems, &bytesafter,
947 (unsigned char **) &data)
949 && type == XA_INTEGER
952 which = (int) data[2] - 1;
954 if (data) free (data);
959 list = GTK_LIST (name_to_widget (toplevel, "list"));
960 apply_changes_and_save (toplevel);
961 gtk_list_select_item (list, which);
962 ensure_selected_item_visible (GTK_WIDGET (list));
963 populate_demo_window (toplevel, which, pair);
969 populate_hack_list (GtkWidget *toplevel, prefs_pair *pair)
971 saver_preferences *p = pair->a;
972 GtkList *list = GTK_LIST (name_to_widget (toplevel, "list"));
973 screenhack **hacks = p->screenhacks;
976 for (h = hacks; *h; h++)
979 char *pretty_name = (h[0]->name
980 ? strdup (h[0]->name)
981 : make_pretty_name (h[0]->command));
983 line = gtk_list_item_new_with_label (pretty_name);
986 gtk_container_add (GTK_CONTAINER (list), line);
987 gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
988 GTK_SIGNAL_FUNC (list_doubleclick_cb),
991 GTK_WIDGET (GTK_BIN(line)->child)->style =
992 gtk_style_copy (GTK_WIDGET (text_line)->style);
994 gtk_widget_show (line);
997 gtk_signal_connect (GTK_OBJECT (list), "select_child",
998 GTK_SIGNAL_FUNC (list_select_cb),
1000 gtk_signal_connect (GTK_OBJECT (list), "unselect_child",
1001 GTK_SIGNAL_FUNC (list_unselect_cb),
1007 populate_prefs_page (GtkWidget *top, prefs_pair *pair)
1009 saver_preferences *p = pair->a;
1012 format_time (s, p->timeout);
1013 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "timeout_text")), s);
1014 format_time (s, p->cycle);
1015 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "cycle_text")), s);
1016 format_time (s, p->lock_timeout);
1017 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "lock_text")), s);
1018 format_time (s, p->passwd_timeout);
1019 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "pass_text")), s);
1020 format_time (s, p->fade_seconds);
1021 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "fade_text")), s);
1022 sprintf (s, "%u", p->fade_ticks);
1023 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "ticks_text")), s);
1025 gtk_toggle_button_set_active (
1026 GTK_TOGGLE_BUTTON (name_to_widget (top, "verbose_button")),
1028 gtk_toggle_button_set_active (
1029 GTK_TOGGLE_BUTTON (name_to_widget (top, "install_button")),
1031 gtk_toggle_button_set_active (
1032 GTK_TOGGLE_BUTTON (name_to_widget (top, "fade_button")),
1034 gtk_toggle_button_set_active (
1035 GTK_TOGGLE_BUTTON (name_to_widget (top, "unfade_button")),
1037 gtk_toggle_button_set_active (
1038 GTK_TOGGLE_BUTTON (name_to_widget (top, "lock_button")),
1043 Bool found_any_writable_cells = False;
1044 Display *dpy = gdk_display;
1045 int nscreens = ScreenCount(dpy);
1047 for (i = 0; i < nscreens; i++)
1049 Screen *s = ScreenOfDisplay (dpy, i);
1050 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1052 found_any_writable_cells = True;
1057 gtk_widget_set_sensitive (
1058 GTK_WIDGET (name_to_widget (top, "fade_label")),
1059 found_any_writable_cells);
1060 gtk_widget_set_sensitive (
1061 GTK_WIDGET (name_to_widget (top, "ticks_label")),
1062 found_any_writable_cells);
1063 gtk_widget_set_sensitive (
1064 GTK_WIDGET (name_to_widget (top, "fade_text")),
1065 found_any_writable_cells);
1066 gtk_widget_set_sensitive (
1067 GTK_WIDGET (name_to_widget (top, "ticks_text")),
1068 found_any_writable_cells);
1069 gtk_widget_set_sensitive (
1070 GTK_WIDGET (name_to_widget (top, "install_button")),
1071 found_any_writable_cells);
1072 gtk_widget_set_sensitive (
1073 GTK_WIDGET (name_to_widget (top, "fade_button")),
1074 found_any_writable_cells);
1075 gtk_widget_set_sensitive (
1076 GTK_WIDGET (name_to_widget (top, "unfade_button")),
1077 found_any_writable_cells);
1084 sensitize_demo_widgets (GtkWidget *toplevel, Bool sensitive_p)
1086 const char *names[] = { "cmd_label", "cmd_text", "enabled",
1087 "visual", "visual_combo",
1090 for (i = 0; i < countof(names); i++)
1092 GtkWidget *w = name_to_widget (toplevel, names[i]);
1093 gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
1096 /* I don't know how to handle these yet... */
1098 const char *names2[] = { "cut_menu", "copy_menu", "paste_menu" };
1099 for (i = 0; i < countof(names2); i++)
1101 GtkWidget *w = name_to_widget (toplevel, names2[i]);
1102 gtk_widget_set_sensitive (GTK_WIDGET(w), False);
1108 /* Even though we've given these text fields a maximum number of characters,
1109 their default size is still about 30 characters wide -- so measure out
1110 a string in their font, and resize them to just fit that.
1113 fix_text_entry_sizes (GtkWidget *toplevel)
1115 const char *names[] = { "timeout_text", "cycle_text", "fade_text",
1116 "ticks_text", "lock_text", "pass_text" };
1121 for (i = 0; i < countof(names); i++)
1123 w = GTK_WIDGET (name_to_widget (toplevel, names[i]));
1125 width = gdk_text_width (w->style->font, "00:00:00_", 9);
1126 gtk_widget_set_usize (w, width, -2);
1129 /* Now fix the size of the combo box.
1131 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "visual_combo"));
1132 w = GTK_COMBO (w)->entry;
1133 width = gdk_text_width (w->style->font, "PseudoColor___", 14);
1134 gtk_widget_set_usize (w, width, -2);
1137 /* Now fix the size of the list.
1139 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "list"));
1140 width = gdk_text_width (w->style->font, "nnnnnnnnnnnnnnnnnnnnnn", 22);
1141 gtk_widget_set_usize (w, width, -2);
1148 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...)
1151 static char *up_arrow_xpm[] = {
1174 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1175 the end of the array (Gtk 1.2.5.) */
1176 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1177 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1180 static char *down_arrow_xpm[] = {
1203 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1204 the end of the array (Gtk 1.2.5.) */
1205 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1206 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1210 pixmapify_buttons (GtkWidget *toplevel)
1214 GtkWidget *pixmapwid;
1218 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "next"));
1219 style = gtk_widget_get_style (w);
1221 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1222 &style->bg[GTK_STATE_NORMAL],
1223 (gchar **) down_arrow_xpm);
1224 pixmapwid = gtk_pixmap_new (pixmap, mask);
1225 gtk_widget_show (pixmapwid);
1226 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1227 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1229 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "prev"));
1230 style = gtk_widget_get_style (w);
1232 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1233 &style->bg[GTK_STATE_NORMAL],
1234 (gchar **) up_arrow_xpm);
1235 pixmapwid = gtk_pixmap_new (pixmap, mask);
1236 gtk_widget_show (pixmapwid);
1237 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1238 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1243 /* Work around a Gtk bug that causes label widgets to wrap text too early.
1247 you_are_not_a_unique_or_beautiful_snowflake (GtkWidget *label,
1248 GtkAllocation *allocation,
1252 GtkWidgetAuxInfo *aux_info;
1254 aux_info = gtk_object_get_data (GTK_OBJECT (label), "gtk-aux-info");
1256 aux_info->width = allocation->width;
1257 aux_info->height = -2;
1261 gtk_widget_size_request (label, &req);
1265 /* Feel the love. Thanks to Nat Friedman for finding this workaround.
1268 eschew_gtk_lossage (GtkWidget *toplevel)
1270 GtkWidgetAuxInfo *aux_info;
1271 GtkWidget *label = GTK_WIDGET (name_to_widget (toplevel, "doc"));
1273 aux_info = g_new0 (GtkWidgetAuxInfo, 1);
1274 aux_info->width = label->allocation.width;
1275 aux_info->height = -2;
1279 gtk_object_set_data (GTK_OBJECT (label), "gtk-aux-info", aux_info);
1281 gtk_signal_connect (GTK_OBJECT (label), "size_allocate",
1282 you_are_not_a_unique_or_beautiful_snowflake, NULL);
1284 gtk_widget_queue_resize (label);
1289 get_hack_blurb (screenhack *hack)
1292 char *prog_name = strdup (hack->command);
1293 char *pretty_name = (hack->name
1294 ? strdup (hack->name)
1295 : make_pretty_name (hack->command));
1296 char doc_name[255], doc_class[255];
1299 for (s = prog_name; *s && !isspace(*s); s++)
1302 s = strrchr (prog_name, '/');
1303 if (s) strcpy (prog_name, s+1);
1305 sprintf (doc_name, "hacks.%s.documentation", pretty_name);
1306 sprintf (doc_class, "hacks.%s.documentation", prog_name);
1310 doc_string = get_string_resource (doc_name, doc_class);
1313 for (s = doc_string; *s; s++)
1317 /* skip over whitespace at beginning of line */
1319 while (*s && (*s == ' ' || *s == '\t'))
1322 else if (*s == ' ' || *s == '\t')
1324 /* compress all other horizontal whitespace. */
1327 for (s2 = s; *s2 && (*s2 == ' ' || *s2 == '\t'); s2++)
1329 if (s2 > s) strcpy (s, s2);
1334 while (*s && isspace (*s)) /* Strip trailing whitespace */
1337 /* Delete whitespace at end of each line. */
1338 for (; s > doc_string; s--)
1339 if (*s == '\n' && (s[-1] == ' ' || s[-1] == '\t'))
1342 s2 > doc_string && (*s2 == ' ' || *s2 == '\t');
1346 if (s2 < s) strcpy (s2, s);
1350 /* Delete leading blank lines. */
1351 for (s = doc_string; *s == '\n'; s++)
1353 if (s > doc_string) strcpy (doc_string, s);
1357 static int doc_installed = 0;
1358 if (doc_installed == 0)
1360 if (get_boolean_resource ("hacks.documentation.isInstalled",
1361 "hacks.documentation.isInstalled"))
1367 if (doc_installed < 0)
1369 strdup ("Error:\n\n"
1370 "The documentation strings do not appear to be "
1371 "installed. This is probably because there is "
1372 "an \"XScreenSaver\" app-defaults file installed "
1373 "that is from an older version of the program. "
1374 "To fix this problem, delete that file, or "
1375 "install a current version (either will work.)");
1377 doc_string = strdup ("");
1385 populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
1387 saver_preferences *p = pair->a;
1388 screenhack *hack = (which >= 0 ? p->screenhacks[which] : 0);
1389 GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
1390 GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
1391 GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
1392 GtkToggleButton *enabled =
1393 GTK_TOGGLE_BUTTON (name_to_widget (toplevel, "enabled"));
1394 GtkCombo *vis = GTK_COMBO (name_to_widget (toplevel, "visual_combo"));
1396 char *pretty_name = (hack
1398 ? strdup (hack->name)
1399 : make_pretty_name (hack->command))
1401 char *doc_string = hack ? get_hack_blurb (hack) : 0;
1403 gtk_frame_set_label (frame, (pretty_name ? pretty_name : ""));
1404 gtk_label_set_text (doc, (doc_string ? doc_string : ""));
1405 gtk_entry_set_text (cmd, (hack ? hack->command : ""));
1406 gtk_entry_set_position (cmd, 0);
1407 gtk_toggle_button_set_active (enabled, (hack ? hack->enabled_p : False));
1408 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry),
1410 ? (hack->visual && *hack->visual
1415 gtk_container_resize_children (GTK_CONTAINER (GTK_WIDGET (doc)->parent));
1417 sensitize_demo_widgets (toplevel, (hack ? True : False));
1419 if (pretty_name) free (pretty_name);
1420 if (doc_string) free (doc_string);
1422 _selected_hack_number = which;
1427 widget_deleter (GtkWidget *widget, gpointer data)
1429 /* #### Well, I want to destroy these widgets, but if I do that, they get
1430 referenced again, and eventually I get a SEGV. So instead of
1431 destroying them, I'll just hide them, and leak a bunch of memory
1432 every time the disk file changes. Go go go Gtk!
1434 #### Ok, that's a lie, I get a crash even if I just hide the widget
1435 and don't ever delete it. Fuck!
1438 gtk_widget_destroy (widget);
1440 gtk_widget_hide (widget);
1446 maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair)
1449 saver_preferences *p = pair->a;
1451 static Bool reentrant_lock = False;
1452 if (reentrant_lock) return 0;
1453 reentrant_lock = True;
1455 if (init_file_changed_p (p))
1457 const char *f = init_file_name();
1462 if (!f || !*f) return 0;
1463 b = (char *) malloc (strlen(f) + 1024);
1466 "file \"%s\" has changed, reloading.\n",
1468 warning_dialog (widget, b, 100);
1473 which = selected_hack_number (widget);
1474 list = GTK_LIST (name_to_widget (widget, "list"));
1475 gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL);
1476 populate_hack_list (widget, pair);
1477 gtk_list_select_item (list, which);
1478 populate_prefs_page (widget, pair);
1479 populate_demo_window (widget, which, pair);
1480 ensure_selected_item_visible (GTK_WIDGET (list));
1485 reentrant_lock = False;
1491 /* The main demo-mode command loop.
1496 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1497 XrmRepresentation *type, XrmValue *value, XPointer closure)
1500 for (i = 0; quarks[i]; i++)
1502 if (bindings[i] == XrmBindTightly)
1503 fprintf (stderr, (i == 0 ? "" : "."));
1504 else if (bindings[i] == XrmBindLoosely)
1505 fprintf (stderr, "*");
1507 fprintf (stderr, " ??? ");
1508 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1511 fprintf (stderr, ": %s\n", (char *) value->addr);
1519 the_network_is_not_the_computer (GtkWidget *parent)
1521 Display *dpy = gdk_display;
1522 char *rversion, *ruser, *rhost;
1523 char *luser, *lhost;
1525 struct passwd *p = getpwuid (getuid ());
1526 const char *d = DisplayString (dpy);
1528 # if defined(HAVE_UNAME)
1530 if (uname (&uts) < 0)
1531 lhost = "<UNKNOWN>";
1533 lhost = uts.nodename;
1535 strcpy (lhost, getenv("SYS$NODE"));
1536 # else /* !HAVE_UNAME && !VMS */
1537 strcat (lhost, "<UNKNOWN>");
1538 # endif /* !HAVE_UNAME && !VMS */
1540 if (p && p->pw_name)
1545 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
1547 /* Make a buffer that's big enough for a number of copies of all the
1548 strings, plus some. */
1549 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
1550 (ruser ? strlen(ruser) : 0) +
1551 (rhost ? strlen(rhost) : 0) +
1558 if (!rversion || !*rversion)
1562 "The XScreenSaver daemon doesn't seem to be running\n"
1563 "on display \"%s\". You can launch it by selecting\n"
1564 "`Restart Daemon' from the File menu, or by typing\n"
1565 "\"xscreensaver &\" in a shell.",
1568 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
1570 /* Warn that the two processes are running as different users.
1574 "%s is running as user \"%s\" on host \"%s\".\n"
1575 "But the xscreensaver managing display \"%s\"\n"
1576 "is running as user \"%s\" on host \"%s\".\n"
1578 "Since they are different users, they won't be reading/writing\n"
1579 "the same ~/.xscreensaver file, so %s isn't\n"
1580 "going to work right.\n"
1582 "Either re-run %s as \"%s\", or re-run\n"
1583 "xscreensaver as \"%s\" (which you can do by\n"
1584 "selecting `Restart Daemon' from the File menu.)\n",
1585 progname, luser, lhost,
1587 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1589 progname, (ruser ? ruser : "???"),
1592 else if (rhost && *rhost && !!strcmp (rhost, lhost))
1594 /* Warn that the two processes are running on different hosts.
1598 "%s is running as user \"%s\" on host \"%s\".\n"
1599 "But the xscreensaver managing display \"%s\"\n"
1600 "is running as user \"%s\" on host \"%s\".\n"
1602 "If those two machines don't share a file system (that is,\n"
1603 "if they don't see the same ~%s/.xscreensaver file) then\n"
1604 "%s won't work right.\n"
1606 "You can restart the daemon on \"%s\" as \"%s\" by\n"
1607 "selecting `Restart Daemon' from the File menu.)",
1608 progname, luser, lhost,
1610 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1615 else if (!!strcmp (rversion, short_version))
1617 /* Warn that the version numbers don't match.
1621 "This is %s version %s.\n"
1622 "But the xscreensaver managing display \"%s\"\n"
1623 "is version %s. This could cause problems.",
1624 progname, short_version,
1631 warning_dialog (parent, msg, 1);
1637 /* We use this error handler so that X errors are preceeded by the name
1638 of the program that generated them.
1641 demo_ehandler (Display *dpy, XErrorEvent *error)
1643 fprintf (stderr, "\nX error in %s:\n", progname);
1644 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
1647 fprintf (stderr, " (nonfatal.)\n");
1652 /* We use this error handler so that Gtk/Gdk errors are preceeded by the name
1653 of the program that generated them; and also that we can ignore one
1654 particular bogus error message that Gdk madly spews.
1657 g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1658 const gchar *message, gpointer user_data)
1660 /* Ignore the message "Got event for unknown window: 0x...".
1661 Apparently some events are coming in for the xscreensaver window
1662 (presumably reply events related to the ClientMessage) and Gdk
1663 feels the need to complain about them. So, just suppress any
1664 messages that look like that one.
1666 if (strstr (message, "unknown window"))
1669 fprintf (stderr, "%s: %s-%s: %s%s", blurb(), log_domain,
1670 (log_level == G_LOG_LEVEL_ERROR ? "error" :
1671 log_level == G_LOG_LEVEL_CRITICAL ? "critical" :
1672 log_level == G_LOG_LEVEL_WARNING ? "warning" :
1673 log_level == G_LOG_LEVEL_MESSAGE ? "message" :
1674 log_level == G_LOG_LEVEL_INFO ? "info" :
1675 log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"),
1677 ((!*message || message[strlen(message)-1] != '\n')
1682 static char *defaults[] = {
1683 #include "XScreenSaver_ad.h"
1688 main (int argc, char **argv)
1691 prefs_pair Pair, *pair;
1692 saver_preferences P, P2, *p, *p2;
1696 Widget toplevel_shell;
1697 GtkWidget *gtk_window;
1698 char *real_progname = argv[0];
1701 s = strrchr (real_progname, '/');
1702 if (s) real_progname = s+1;
1709 memset (p, 0, sizeof (*p));
1710 memset (p2, 0, sizeof (*p2));
1712 global_prefs_pair = pair; /* I hate C so much... */
1714 progname = real_progname;
1716 short_version = (char *) malloc (5);
1717 memcpy (short_version, screensaver_id + 17, 4);
1718 short_version [4] = 0;
1721 /* Register our error message logger for every ``log domain'' known.
1722 There's no way to do this globally, so I grepped the Gtk/Gdk sources
1723 for all of the domains that seem to be in use.
1726 const char * const domains[] = { "Gtk", "Gdk", "GLib", "GModule",
1727 "GThread", "Gnome", "GnomeUI", 0 };
1728 for (i = 0; domains[i]; i++)
1729 g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0);
1732 /* This is gross, but Gtk understands --display and not -display...
1734 for (i = 1; i < argc; i++)
1735 if (argv[i][0] && argv[i][1] &&
1736 !strncmp(argv[i], "-display", strlen(argv[i])))
1737 argv[i] = "--display";
1739 /* Let Gtk open the X connection, then initialize Xt to use that
1740 same connection. Doctor Frankenstein would be proud. */
1741 gtk_init (&argc, &argv);
1744 /* We must read exactly the same resources as xscreensaver.
1745 That means we must have both the same progclass *and* progname,
1746 at least as far as the resource database is concerned. So,
1747 put "xscreensaver" in argv[0] while initializing Xt.
1749 argv[0] = "xscreensaver";
1753 /* Teach Xt to use the Display that Gtk/Gdk have already opened.
1755 XtToolkitInitialize ();
1756 app = XtCreateApplicationContext ();
1758 XtAppSetFallbackResources (app, defaults);
1759 XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv);
1760 toplevel_shell = XtAppCreateShell (progname, progclass,
1761 applicationShellWidgetClass,
1764 dpy = XtDisplay (toplevel_shell);
1765 db = XtDatabase (dpy);
1766 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
1767 XSetErrorHandler (demo_ehandler);
1770 /* After doing Xt-style command-line processing, complain about any
1771 unrecognized command-line arguments.
1773 for (i = 1; i < argc; i++)
1776 if (s[0] == '-' && s[1] == '-')
1778 if (!strcmp (s, "-prefs"))
1782 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n",
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 /* Print out all the resources we read. */
1807 XrmName name = { 0 };
1808 XrmClass class = { 0 };
1810 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1816 /* Intern the atoms that xscreensaver_command() needs.
1818 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1819 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
1820 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
1821 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
1822 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
1823 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
1824 XA_SELECT = XInternAtom (dpy, "SELECT", False);
1825 XA_DEMO = XInternAtom (dpy, "DEMO", False);
1826 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
1827 XA_BLANK = XInternAtom (dpy, "BLANK", False);
1828 XA_LOCK = XInternAtom (dpy, "LOCK", False);
1829 XA_EXIT = XInternAtom (dpy, "EXIT", False);
1830 XA_RESTART = XInternAtom (dpy, "RESTART", False);
1833 /* Create the window and all its widgets.
1835 gtk_window = create_xscreensaver_demo ();
1837 /* Set the window's title. */
1840 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1841 char *s1, *s2, *s3, *s4;
1842 s1 = (char *) strchr(v, ' '); s1++;
1843 s2 = (char *) strchr(s1, ' ');
1844 s3 = (char *) strchr(v, '('); s3++;
1845 s4 = (char *) strchr(s3, ')');
1848 sprintf (title, "%.50s %.50s, %.50s", progclass, s1, s3);
1849 gtk_window_set_title (GTK_WINDOW (gtk_window), title);
1853 /* Various other widget initializations...
1855 gtk_signal_connect (GTK_OBJECT (gtk_window), "delete_event",
1856 GTK_SIGNAL_FUNC (wm_close_cb), NULL);
1858 populate_hack_list (gtk_window, pair);
1859 populate_prefs_page (gtk_window, pair);
1860 sensitize_demo_widgets (gtk_window, False);
1861 fix_text_entry_sizes (gtk_window);
1862 scroll_to_current_hack (gtk_window, pair);
1863 gtk_widget_show (gtk_window);
1865 /* The next three calls must come after gtk_widget_show(). */
1866 pixmapify_buttons (gtk_window);
1867 eschew_gtk_lossage (gtk_window);
1868 ensure_selected_item_visible (GTK_WIDGET(name_to_widget(gtk_window,"list")));
1870 /* Handle the -prefs command-line argument. */
1873 GtkNotebook *notebook =
1874 GTK_NOTEBOOK (name_to_widget (gtk_window, "notebook"));
1875 gtk_notebook_set_page (notebook, 1);
1878 /* Issue any warnings about the running xscreensaver daemon. */
1879 the_network_is_not_the_computer (gtk_window);
1881 /* Run the Gtk event loop, and not the Xt event loop. This means that
1882 if there were Xt timers or fds registered, they would never get serviced,
1883 and if there were any Xt widgets, they would never have events delivered.
1884 Fortunately, we're using Gtk for all of the UI, and only initialized
1885 Xt so that we could process the command line and use the X resource
1892 #endif /* HAVE_GTK -- whole file */