1 /* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
2 * xscreensaver, Copyright (c) 1993-2001 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 */
38 #include <X11/Xproto.h> /* for CARD32 */
39 #include <X11/Xatom.h> /* for XA_INTEGER */
40 #include <X11/Intrinsic.h>
41 #include <X11/StringDefs.h>
43 /* We don't actually use any widget internals, but these are included
44 so that gdb will have debug info for the widgets... */
45 #include <X11/IntrinsicP.h>
46 #include <X11/ShellP.h>
50 # include <X11/Xmu/Error.h>
52 # include <Xmu/Error.h>
62 # include <capplet-widget.h>
69 #include "resources.h" /* for parse_time() */
70 #include "visual.h" /* for has_writable_cells() */
71 #include "remote.h" /* for xscreensaver_command() */
74 #include "logo-50.xpm"
75 #include "logo-180.xpm"
77 #include "demo-Gtk-widgets.h"
84 #define countof(x) (sizeof((x))/sizeof((*x)))
88 char *progclass = "XScreenSaver";
91 static Bool crapplet_p = False;
92 static Bool initializing_p;
93 static GtkWidget *toplevel_widget;
96 saver_preferences *a, *b;
99 static void *global_prefs_pair; /* I hate C so much... */
101 char *blurb (void) { return progname; }
103 static char *short_version = 0;
106 Atom XA_SCREENSAVER, XA_SCREENSAVER_RESPONSE, XA_SCREENSAVER_VERSION;
107 Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_SELECT, XA_DEMO;
108 Atom XA_ACTIVATE, XA_BLANK, XA_LOCK, XA_RESTART, XA_EXIT;
111 static void populate_demo_window (GtkWidget *toplevel,
112 int which, prefs_pair *pair);
113 static void populate_prefs_page (GtkWidget *top, prefs_pair *pair);
114 static int apply_changes_and_save (GtkWidget *widget);
115 static int maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair);
116 static void await_xscreensaver (GtkWidget *widget);
119 /* Some random utility functions
123 name_to_widget (GtkWidget *widget, const char *name)
125 return (GtkWidget *) gtk_object_get_data (GTK_OBJECT(toplevel_widget), name);
129 /* Why this behavior isn't automatic in *either* toolkit, I'll never know.
130 Takes a scroller, viewport, or list as an argument.
133 ensure_selected_item_visible (GtkWidget *widget)
135 GtkScrolledWindow *scroller = 0;
137 GtkList *list_widget = 0;
141 GtkWidget *selected = 0;
144 gint parent_h, child_y, child_h, children_h, ignore;
145 double ratio_t, ratio_b;
147 if (GTK_IS_SCROLLED_WINDOW (widget))
149 scroller = GTK_SCROLLED_WINDOW (widget);
150 vp = GTK_VIEWPORT (GTK_BIN (scroller)->child);
151 list_widget = GTK_LIST (GTK_BIN(vp)->child);
153 else if (GTK_IS_VIEWPORT (widget))
155 vp = GTK_VIEWPORT (widget);
156 scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
157 list_widget = GTK_LIST (GTK_BIN(vp)->child);
159 else if (GTK_IS_LIST (widget))
161 list_widget = GTK_LIST (widget);
162 vp = GTK_VIEWPORT (GTK_WIDGET (list_widget)->parent);
163 scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
168 slist = list_widget->selection;
169 selected = (slist ? GTK_WIDGET (slist->data) : 0);
173 which = gtk_list_child_position (list_widget, GTK_WIDGET (selected));
175 for (kids = gtk_container_children (GTK_CONTAINER (list_widget));
176 kids; kids = kids->next)
179 adj = gtk_scrolled_window_get_vadjustment (scroller);
181 gdk_window_get_geometry (GTK_WIDGET(vp)->window,
182 &ignore, &ignore, &ignore, &parent_h, &ignore);
183 gdk_window_get_geometry (GTK_WIDGET(selected)->window,
184 &ignore, &child_y, &ignore, &child_h, &ignore);
185 children_h = nkids * child_h;
187 ratio_t = ((double) child_y) / ((double) children_h);
188 ratio_b = ((double) child_y + child_h) / ((double) children_h);
190 if (adj->upper == 0.0) /* no items in list */
193 if (ratio_t < (adj->value / adj->upper) ||
194 ratio_b > ((adj->value + adj->page_size) / adj->upper))
197 int slop = parent_h * 0.75; /* how much to overshoot by */
199 if (ratio_t < (adj->value / adj->upper))
201 double ratio_w = ((double) parent_h) / ((double) children_h);
202 double ratio_l = (ratio_b - ratio_t);
203 target = ((ratio_t - ratio_w + ratio_l) * adj->upper);
206 else /* if (ratio_b > ((adj->value + adj->page_size) / adj->upper))*/
208 target = ratio_t * adj->upper;
212 if (target > adj->upper - adj->page_size)
213 target = adj->upper - adj->page_size;
217 gtk_adjustment_set_value (adj, target);
222 warning_dialog_dismiss_cb (GtkWidget *widget, 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));
231 void restart_menu_cb (GtkWidget *widget, gpointer user_data);
233 static void warning_dialog_restart_cb (GtkWidget *widget, gpointer user_data)
235 restart_menu_cb (widget, user_data);
236 warning_dialog_dismiss_cb (widget, user_data);
240 warning_dialog (GtkWidget *parent, const char *message,
241 Boolean restart_button_p, int center)
243 char *msg = strdup (message);
246 GtkWidget *dialog = gtk_dialog_new ();
247 GtkWidget *label = 0;
249 GtkWidget *cancel = 0;
252 while (parent->parent)
253 parent = parent->parent;
255 if (!GTK_WIDGET (parent)->window) /* too early to pop up transient dialogs */
262 char *s = strchr (head, '\n');
265 sprintf (name, "label%d", i++);
268 label = gtk_label_new (head);
272 GTK_WIDGET (label)->style =
273 gtk_style_copy (GTK_WIDGET (label)->style);
274 GTK_WIDGET (label)->style->font =
275 gdk_font_load (get_string_resource("warning_dialog.headingFont",
277 gtk_widget_set_style (GTK_WIDGET (label),
278 GTK_WIDGET (label)->style);
282 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
283 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
284 label, TRUE, TRUE, 0);
285 gtk_widget_show (label);
296 label = gtk_label_new ("");
297 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
298 label, TRUE, TRUE, 0);
299 gtk_widget_show (label);
301 label = gtk_hbutton_box_new ();
302 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
303 label, TRUE, TRUE, 0);
305 ok = gtk_button_new_with_label ("OK");
306 gtk_container_add (GTK_CONTAINER (label), ok);
308 if (restart_button_p)
310 cancel = gtk_button_new_with_label ("Cancel");
311 gtk_container_add (GTK_CONTAINER (label), cancel);
314 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
315 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
316 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
317 gtk_widget_show (ok);
319 gtk_widget_show (cancel);
320 gtk_widget_show (label);
321 gtk_widget_show (dialog);
322 /* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
324 if (restart_button_p)
326 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
327 GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
329 gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
330 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
335 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
336 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
340 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
341 GTK_WIDGET (parent)->window);
343 gdk_window_show (GTK_WIDGET (dialog)->window);
344 gdk_window_raise (GTK_WIDGET (dialog)->window);
351 run_cmd (GtkWidget *widget, Atom command, int arg)
356 apply_changes_and_save (widget);
357 status = xscreensaver_command (GDK_DISPLAY(), command, arg, False, &err);
362 sprintf (buf, "Error:\n\n%s", err);
364 strcpy (buf, "Unknown error!");
365 warning_dialog (widget, buf, False, 100);
372 run_hack (GtkWidget *widget, int which, Bool report_errors_p)
374 if (which < 0) return;
375 apply_changes_and_save (widget);
377 run_cmd (widget, XA_DEMO, which + 1);
381 xscreensaver_command (GDK_DISPLAY(), XA_DEMO, which + 1, False, &s);
392 exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
394 apply_changes_and_save (GTK_WIDGET (menuitem));
399 wm_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
401 apply_changes_and_save (widget);
407 cut_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
410 warning_dialog (GTK_WIDGET (menuitem),
412 "cut unimplemented\n", False, 1);
417 copy_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
420 warning_dialog (GTK_WIDGET (menuitem),
422 "copy unimplemented\n", False, 1);
427 paste_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
430 warning_dialog (GTK_WIDGET (menuitem),
432 "paste unimplemented\n", False, 1);
437 about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
440 char *vers = strdup (screensaver_id + 4);
443 char *desc = "For updates, check http://www.jwz.org/xscreensaver/";
445 s = strchr (vers, ',');
449 sprintf(copy, "Copyright \251 1991-2001 %s", s);
451 sprintf (msg, "%s\n\n%s", copy, desc);
453 /* I can't make gnome_about_new() work here -- it starts dying in
454 gdk_imlib_get_visual() under gnome_about_new(). If this worked,
455 then this might be the thing to do:
459 const gchar *auth[] = { 0 };
460 GtkWidget *about = gnome_about_new (progclass, vers, "", auth, desc,
462 gtk_widget_show (about);
464 #else / * GTK but not GNOME * /
468 GdkColormap *colormap;
469 GdkPixmap *gdkpixmap;
472 GtkWidget *dialog = gtk_dialog_new ();
473 GtkWidget *hbox, *icon, *vbox, *label1, *label2, *hb, *ok;
474 GtkWidget *parent = GTK_WIDGET (menuitem);
475 while (parent->parent)
476 parent = parent->parent;
478 hbox = gtk_hbox_new (FALSE, 20);
479 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
480 hbox, TRUE, TRUE, 0);
482 colormap = gtk_widget_get_colormap (parent);
484 gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, NULL,
485 (gchar **) logo_180_xpm);
486 icon = gtk_pixmap_new (gdkpixmap, mask);
487 gtk_misc_set_padding (GTK_MISC (icon), 10, 10);
489 gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
491 vbox = gtk_vbox_new (FALSE, 0);
492 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
494 label1 = gtk_label_new (vers);
495 gtk_box_pack_start (GTK_BOX (vbox), label1, TRUE, TRUE, 0);
496 gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT);
497 gtk_misc_set_alignment (GTK_MISC (label1), 0.0, 0.75);
499 GTK_WIDGET (label1)->style = gtk_style_copy (GTK_WIDGET (label1)->style);
500 GTK_WIDGET (label1)->style->font =
501 gdk_font_load (get_string_resource ("about.headingFont","Dialog.Font"));
502 gtk_widget_set_style (GTK_WIDGET (label1), GTK_WIDGET (label1)->style);
504 label2 = gtk_label_new (msg);
505 gtk_box_pack_start (GTK_BOX (vbox), label2, TRUE, TRUE, 0);
506 gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
507 gtk_misc_set_alignment (GTK_MISC (label2), 0.0, 0.25);
509 GTK_WIDGET (label2)->style = gtk_style_copy (GTK_WIDGET (label2)->style);
510 GTK_WIDGET (label2)->style->font =
511 gdk_font_load (get_string_resource ("about.bodyFont","Dialog.Font"));
512 gtk_widget_set_style (GTK_WIDGET (label2), GTK_WIDGET (label2)->style);
514 hb = gtk_hbutton_box_new ();
516 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
519 ok = gtk_button_new_with_label ("OK");
520 gtk_container_add (GTK_CONTAINER (hb), ok);
522 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
523 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
524 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
526 gtk_widget_show (hbox);
527 gtk_widget_show (icon);
528 gtk_widget_show (vbox);
529 gtk_widget_show (label1);
530 gtk_widget_show (label2);
531 gtk_widget_show (hb);
532 gtk_widget_show (ok);
533 gtk_widget_show (dialog);
535 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
536 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
538 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
539 GTK_WIDGET (parent)->window);
540 gdk_window_show (GTK_WIDGET (dialog)->window);
541 gdk_window_raise (GTK_WIDGET (dialog)->window);
547 doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
549 /* prefs_pair *pair = (prefs_pair *) client_data; */
550 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
552 saver_preferences *p = pair->a;
555 if (!p->help_url || !*p->help_url)
557 warning_dialog (GTK_WIDGET (menuitem),
559 "No Help URL has been specified.\n", False, 100);
563 help_command = (char *) malloc (strlen (p->load_url_command) +
564 (strlen (p->help_url) * 2) + 20);
565 strcpy (help_command, "( ");
566 sprintf (help_command + strlen(help_command),
567 p->load_url_command, p->help_url, p->help_url);
568 strcat (help_command, " ) &");
569 system (help_command);
575 activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
577 run_cmd (GTK_WIDGET (menuitem), XA_ACTIVATE, 0);
582 lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
584 run_cmd (GTK_WIDGET (menuitem), XA_LOCK, 0);
589 kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
591 run_cmd (GTK_WIDGET (menuitem), XA_EXIT, 0);
596 restart_menu_cb (GtkWidget *widget, gpointer user_data)
599 run_cmd (GTK_WIDGET (widget), XA_RESTART, 0);
601 apply_changes_and_save (GTK_WIDGET (widget));
602 xscreensaver_command (GDK_DISPLAY(), XA_EXIT, 0, False, NULL);
604 system ("xscreensaver -nosplash &");
607 await_xscreensaver (GTK_WIDGET (widget));
611 await_xscreensaver (GtkWidget *widget)
615 Display *dpy = GDK_DISPLAY();
616 /* GtkWidget *dialog = 0;*/
619 while (!rversion && (--countdown > 0))
621 /* Check for the version of the running xscreensaver... */
622 server_xscreensaver_version (dpy, &rversion, 0, 0);
624 /* If it's not there yet, wait a second... */
628 /* if (dialog) gtk_widget_destroy (dialog);*/
637 /* Timed out, no screensaver running. */
640 Bool root_p = (geteuid () == 0);
644 "The xscreensaver daemon did not start up properly.\n"
649 "You are running as root. This usually means that xscreensaver\n"
650 "was unable to contact your X server because access control is\n"
651 "turned on. Try running this command:\n"
653 " xhost +localhost\n"
655 "and then selecting `File / Restart Daemon'.\n"
657 "Note that turning off access control will allow anyone logged\n"
658 "on to this machine to access your screen, which might be\n"
659 "considered a security problem. Please read the xscreensaver\n"
660 "manual and FAQ for more information.\n"
662 "You shouldn't run X as root. Instead, you should log in as a\n"
663 "normal user, and `su' as necessary.");
665 strcat (buf, "Please check your $PATH and permissions.");
667 warning_dialog (widget, buf, False, 1);
672 static int _selected_hack_number = -1;
675 selected_hack_number (GtkWidget *toplevel)
678 GtkViewport *vp = GTK_VIEWPORT (name_to_widget (toplevel, "viewport"));
679 GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
680 GList *slist = list_widget->selection;
681 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
682 int which = (selected
683 ? gtk_list_child_position (list_widget, GTK_WIDGET (selected))
687 return _selected_hack_number;
693 demo_write_init_file (GtkWidget *widget, saver_preferences *p)
695 if (!write_init_file (p, short_version, False))
699 const char *f = init_file_name();
701 warning_dialog (widget,
702 "Error:\n\nCouldn't determine init file name!\n",
706 char *b = (char *) malloc (strlen(f) + 1024);
707 sprintf (b, "Error:\n\nCouldn't write %s\n", f);
708 warning_dialog (widget, b, False, 100);
717 apply_changes_and_save_1 (GtkWidget *widget)
719 /* prefs_pair *pair = (prefs_pair *) client_data; */
720 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
721 saver_preferences *p = pair->a;
722 GtkList *list_widget =
723 GTK_LIST (name_to_widget (widget, "list"));
724 int which = selected_hack_number (widget);
726 GtkEntry *cmd = GTK_ENTRY (name_to_widget (widget, "cmd_text"));
727 GtkToggleButton *enabled =
728 GTK_TOGGLE_BUTTON (name_to_widget (widget, "enabled"));
729 GtkCombo *vis = GTK_COMBO (name_to_widget (widget, "visual_combo"));
731 Bool enabled_p = gtk_toggle_button_get_active (enabled);
732 const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
733 const char *command = gtk_entry_get_text (cmd);
738 if (which < 0) return -1;
740 if (maybe_reload_init_file (widget, pair) != 0)
743 /* Sanity-check and canonicalize whatever the user typed into the combo box.
745 if (!strcasecmp (visual, "")) visual = "";
746 else if (!strcasecmp (visual, "any")) visual = "";
747 else if (!strcasecmp (visual, "default")) visual = "Default";
748 else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
749 else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
750 else if (!strcasecmp (visual, "best")) visual = "Best";
751 else if (!strcasecmp (visual, "mono")) visual = "Mono";
752 else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
753 else if (!strcasecmp (visual, "gray")) visual = "Gray";
754 else if (!strcasecmp (visual, "grey")) visual = "Gray";
755 else if (!strcasecmp (visual, "color")) visual = "Color";
756 else if (!strcasecmp (visual, "gl")) visual = "GL";
757 else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
758 else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
759 else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
760 else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
761 else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
762 else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
763 else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
764 else if (1 == sscanf (visual, " %ld %c", &id, &c)) ;
765 else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
768 gdk_beep (); /* unparsable */
770 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");
773 ensure_selected_item_visible (GTK_WIDGET (list_widget));
775 if (!p->screenhacks[which]->visual)
776 p->screenhacks[which]->visual = strdup ("");
777 if (!p->screenhacks[which]->command)
778 p->screenhacks[which]->command = strdup ("");
780 if (p->screenhacks[which]->enabled_p != enabled_p ||
781 !!strcasecmp (p->screenhacks[which]->visual, visual) ||
782 !!strcasecmp (p->screenhacks[which]->command, command))
784 /* Something was changed -- store results into the struct,
787 free (p->screenhacks[which]->visual);
788 free (p->screenhacks[which]->command);
789 p->screenhacks[which]->visual = strdup (visual);
790 p->screenhacks[which]->command = strdup (command);
791 p->screenhacks[which]->enabled_p = enabled_p;
793 return demo_write_init_file (widget, p);
796 /* No changes made */
800 void prefs_ok_cb (GtkButton *button, gpointer user_data);
803 apply_changes_and_save (GtkWidget *widget)
805 prefs_ok_cb ((GtkButton *) widget, 0);
806 return apply_changes_and_save_1 (widget);
811 run_this_cb (GtkButton *button, gpointer user_data)
813 int which = selected_hack_number (GTK_WIDGET (button));
814 if (which < 0) return;
815 if (0 == apply_changes_and_save (GTK_WIDGET (button)))
816 run_hack (GTK_WIDGET (button), which, True);
821 manual_cb (GtkButton *button, gpointer user_data)
823 /* prefs_pair *pair = (prefs_pair *) client_data; */
824 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
825 saver_preferences *p = pair->a;
826 GtkList *list_widget =
827 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
828 int which = selected_hack_number (GTK_WIDGET (button));
829 char *name, *name2, *cmd, *s;
830 if (which < 0) return;
831 apply_changes_and_save (GTK_WIDGET (button));
832 ensure_selected_item_visible (GTK_WIDGET (list_widget));
834 name = strdup (p->screenhacks[which]->command);
836 while (isspace (*name2)) name2++;
838 while (*s && !isspace (*s)) s++;
840 s = strrchr (name2, '/');
843 cmd = get_string_resource ("manualCommand", "ManualCommand");
846 char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
848 sprintf (cmd2 + strlen (cmd2),
850 name2, name2, name2, name2);
851 strcat (cmd2, " ) &");
857 warning_dialog (GTK_WIDGET (button),
858 "Error:\n\nno `manualCommand' resource set.",
867 run_next_cb (GtkButton *button, gpointer user_data)
869 /* prefs_pair *pair = (prefs_pair *) client_data; */
870 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
871 saver_preferences *p = pair->a;
873 GtkList *list_widget =
874 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
875 int which = selected_hack_number (GTK_WIDGET (button));
882 if (which >= p->screenhacks_count)
885 apply_changes_and_save (GTK_WIDGET (button));
886 gtk_list_select_item (GTK_LIST (list_widget), which);
887 ensure_selected_item_visible (GTK_WIDGET (list_widget));
888 populate_demo_window (GTK_WIDGET (button), which, pair);
889 run_hack (GTK_WIDGET (button), which, False);
894 run_prev_cb (GtkButton *button, gpointer user_data)
896 /* prefs_pair *pair = (prefs_pair *) client_data; */
897 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
898 saver_preferences *p = pair->a;
900 GtkList *list_widget =
901 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
902 int which = selected_hack_number (GTK_WIDGET (button));
905 which = p->screenhacks_count - 1;
910 which = p->screenhacks_count - 1;
912 apply_changes_and_save (GTK_WIDGET (button));
913 gtk_list_select_item (GTK_LIST (list_widget), which);
914 ensure_selected_item_visible (GTK_WIDGET (list_widget));
915 populate_demo_window (GTK_WIDGET (button), which, pair);
916 run_hack (GTK_WIDGET (button), which, False);
920 /* Helper for the text fields that contain time specifications:
921 this parses the text, and does error checking.
924 hack_time_text (GtkWidget *widget, const char *line, Time *store, Bool sec_p)
929 value = parse_time ((char *) line, sec_p, True);
930 value *= 1000; /* Time measures in microseconds */
936 "Unparsable time format: \"%s\"\n",
938 warning_dialog (widget, b, False, 100);
947 directory_p (const char *path)
952 else if (stat (path, &st))
954 else if (!S_ISDIR (st.st_mode))
961 normalize_directory (const char *path)
967 p2 = (char *) malloc (L + 2);
969 if (p2[L-1] == '/') /* remove trailing slash */
972 for (s = p2; s && *s; s++)
975 (!strncmp (s, "/../", 4) || /* delete "XYZ/../" */
976 !strncmp (s, "/..\000", 4))) /* delete "XYZ/..$" */
979 while (s0 > p2 && s0[-1] != '/')
989 else if (*s == '/' && !strncmp (s, "/./", 3)) /* delete "/./" */
990 strcpy (s, s+2), s--;
991 else if (*s == '/' && !strncmp (s, "/.\000", 3)) /* delete "/.$" */
995 for (s = p2; s && *s; s++) /* normalize consecutive slashes */
996 while (s[0] == '/' && s[1] == '/')
1004 prefs_ok_cb (GtkButton *button, gpointer user_data)
1006 /* prefs_pair *pair = (prefs_pair *) client_data; */
1007 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1009 saver_preferences *p = pair->a;
1010 saver_preferences *p2 = pair->b;
1011 Bool changed = False;
1013 # define SECONDS(field, name) \
1014 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
1015 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
1019 # define MINUTES(field, name) \
1020 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
1021 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
1025 # define INTEGER(field, name) do { \
1026 char *line = gtk_entry_get_text (\
1027 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
1028 unsigned int value; \
1032 else if (sscanf (line, "%u%c", &value, &c) != 1) \
1035 sprintf (b, "Error:\n\n" "Not an integer: \"%s\"\n", line); \
1036 warning_dialog (GTK_WIDGET (button), b, False, 100); \
1042 # define PATHNAME(field, name) do { \
1043 char *line = gtk_entry_get_text (\
1044 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
1047 else if (!directory_p (line)) \
1050 sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n", line); \
1051 warning_dialog (GTK_WIDGET (button), b, False, 100); \
1052 if ((field)) free ((field)); \
1053 (field) = strdup(line); \
1056 if ((field)) free ((field)); \
1057 (field) = strdup(line); \
1061 # define CHECKBOX(field, name) \
1062 field = gtk_toggle_button_get_active (\
1063 GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET(button), (name))))
1065 MINUTES (&p2->timeout, "timeout_text");
1066 MINUTES (&p2->cycle, "cycle_text");
1067 CHECKBOX (p2->lock_p, "lock_button");
1068 MINUTES (&p2->lock_timeout, "lock_text");
1070 CHECKBOX (p2->dpms_enabled_p, "dpms_button");
1071 MINUTES (&p2->dpms_standby, "dpms_standby_text");
1072 MINUTES (&p2->dpms_suspend, "dpms_suspend_text");
1073 MINUTES (&p2->dpms_off, "dpms_off_text");
1075 CHECKBOX (p2->grab_desktop_p, "grab_desk_button");
1076 CHECKBOX (p2->grab_video_p, "grab_video_button");
1077 CHECKBOX (p2->random_image_p, "grab_image_button");
1078 PATHNAME (p2->image_directory, "image_text");
1080 CHECKBOX (p2->verbose_p, "verbose_button");
1081 CHECKBOX (p2->capture_stderr_p, "capture_button");
1082 CHECKBOX (p2->splash_p, "splash_button");
1084 CHECKBOX (p2->install_cmap_p, "install_button");
1085 CHECKBOX (p2->fade_p, "fade_button");
1086 CHECKBOX (p2->unfade_p, "unfade_button");
1087 SECONDS (&p2->fade_seconds, "fade_text");
1095 # define COPY(field) \
1096 if (p->field != p2->field) changed = True; \
1097 p->field = p2->field
1104 COPY(dpms_enabled_p);
1109 COPY (grab_desktop_p);
1110 COPY (grab_video_p);
1111 COPY (random_image_p);
1113 if (!p->image_directory ||
1114 !p2->image_directory ||
1115 strcmp(p->image_directory, p2->image_directory))
1117 if (p->image_directory && p->image_directory != p2->image_directory)
1118 free (p->image_directory);
1119 p->image_directory = normalize_directory (p2->image_directory);
1120 if (p2->image_directory) free (p2->image_directory);
1121 p2->image_directory = 0;
1124 COPY(capture_stderr_p);
1127 COPY(install_cmap_p);
1133 populate_prefs_page (GTK_WIDGET (button), pair);
1137 Display *dpy = GDK_DISPLAY();
1138 sync_server_dpms_settings (dpy, p->dpms_enabled_p,
1139 p->dpms_standby / 1000,
1140 p->dpms_suspend / 1000,
1144 demo_write_init_file (GTK_WIDGET (button), p);
1150 prefs_cancel_cb (GtkButton *button, gpointer user_data)
1152 /* prefs_pair *pair = (prefs_pair *) client_data; */
1153 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1155 *pair->b = *pair->a;
1156 populate_prefs_page (GTK_WIDGET (button), pair);
1161 pref_changed_cb (GtkButton *button, gpointer user_data)
1163 if (! initializing_p)
1164 apply_changes_and_save (GTK_WIDGET (button));
1169 list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
1170 gpointer client_data)
1172 if (event->type == GDK_2BUTTON_PRESS)
1174 GtkList *list = GTK_LIST (name_to_widget (button, "list"));
1175 int which = gtk_list_child_position (list, GTK_WIDGET (button));
1178 run_hack (GTK_WIDGET (button), which, True);
1186 list_select_cb (GtkList *list, GtkWidget *child)
1188 /* prefs_pair *pair = (prefs_pair *) client_data; */
1189 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1191 int which = gtk_list_child_position (list, GTK_WIDGET (child));
1192 apply_changes_and_save (GTK_WIDGET (list));
1193 populate_demo_window (GTK_WIDGET (list), which, pair);
1197 list_unselect_cb (GtkList *list, GtkWidget *child)
1199 /* prefs_pair *pair = (prefs_pair *) client_data; */
1200 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1202 apply_changes_and_save (GTK_WIDGET (list));
1203 populate_demo_window (GTK_WIDGET (list), -1, pair);
1207 static int updating_enabled_cb = 0; /* kludge to make sure that enabled_cb
1208 is only run by user action, not by
1211 /* Called when the checkboxes that are in the left column of the
1212 scrolling list are clicked. This both populates the right pane
1213 (just as clicking on the label (really, listitem) does) and
1214 also syncs this checkbox with the right pane Enabled checkbox.
1217 list_checkbox_cb (GtkWidget *cb, gpointer client_data)
1219 prefs_pair *pair = (prefs_pair *) client_data;
1221 GtkWidget *line_hbox = GTK_WIDGET (cb)->parent;
1222 GtkWidget *line = GTK_WIDGET (line_hbox)->parent;
1224 GtkList *list = GTK_LIST (GTK_WIDGET (line)->parent);
1225 GtkViewport *vp = GTK_VIEWPORT (GTK_WIDGET (list)->parent);
1226 GtkScrolledWindow *scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
1230 GtkToggleButton *enabled =
1231 GTK_TOGGLE_BUTTON (name_to_widget (cb, "enabled"));
1233 int which = gtk_list_child_position (list, line);
1235 /* remember previous scroll position of the top of the list */
1236 adj = gtk_scrolled_window_get_vadjustment (scroller);
1237 scroll_top = adj->value;
1239 apply_changes_and_save (GTK_WIDGET (list));
1240 gtk_list_select_item (list, which);
1241 /* ensure_selected_item_visible (GTK_WIDGET (list)); */
1242 populate_demo_window (GTK_WIDGET (list), which, pair);
1244 updating_enabled_cb++;
1245 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (enabled),
1246 GTK_TOGGLE_BUTTON (cb)->active);
1247 updating_enabled_cb--;
1249 /* restore the previous scroll position of the top of the list.
1250 this is weak, but I don't really know why it's moving... */
1251 gtk_adjustment_set_value (adj, scroll_top);
1255 /* Called when the right pane Enabled checkbox is clicked. This syncs
1256 the corresponding checkbox inside the scrolling list to the state
1260 enabled_cb (GtkWidget *cb, gpointer client_data)
1262 int which = selected_hack_number (cb);
1264 if (updating_enabled_cb) return;
1268 GtkList *list = GTK_LIST (name_to_widget (cb, "list"));
1269 GList *kids = GTK_LIST (list)->children;
1270 GtkWidget *line = GTK_WIDGET (g_list_nth_data (kids, which));
1271 GtkWidget *line_hbox = GTK_WIDGET (GTK_BIN (line)->child);
1272 GtkWidget *line_check =
1273 GTK_WIDGET (gtk_container_children (GTK_CONTAINER (line_hbox))->data);
1275 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (line_check),
1276 GTK_TOGGLE_BUTTON (cb)->active);
1284 GtkFileSelection *widget;
1285 } file_selection_data;
1290 store_image_directory (GtkWidget *button, gpointer user_data)
1292 file_selection_data *fsd = (file_selection_data *) user_data;
1293 prefs_pair *pair = fsd->pair;
1294 GtkFileSelection *selector = fsd->widget;
1295 GtkWidget *top = toplevel_widget;
1296 saver_preferences *p = pair->a;
1297 char *path = gtk_file_selection_get_filename (selector);
1299 if (p->image_directory && !strcmp(p->image_directory, path))
1300 return; /* no change */
1302 if (!directory_p (path))
1305 sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n", path);
1306 warning_dialog (GTK_WIDGET (top), b, False, 100);
1310 if (p->image_directory) free (p->image_directory);
1311 p->image_directory = normalize_directory (path);
1313 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "image_text")),
1314 (p->image_directory ? p->image_directory : ""));
1315 demo_write_init_file (GTK_WIDGET (top), p);
1320 browse_image_dir_cancel (GtkWidget *button, gpointer user_data)
1322 file_selection_data *fsd = (file_selection_data *) user_data;
1323 gtk_widget_hide (GTK_WIDGET (fsd->widget));
1327 browse_image_dir_ok (GtkWidget *button, gpointer user_data)
1329 browse_image_dir_cancel (button, user_data);
1330 store_image_directory (button, user_data);
1334 browse_image_dir_close (GtkWidget *widget, GdkEvent *event, gpointer user_data)
1336 browse_image_dir_cancel (widget, user_data);
1341 browse_image_dir_cb (GtkButton *button, gpointer user_data)
1343 /* prefs_pair *pair = (prefs_pair *) client_data; */
1344 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1345 saver_preferences *p = pair->a;
1346 static file_selection_data *fsd = 0;
1348 GtkFileSelection *selector = GTK_FILE_SELECTION(
1349 gtk_file_selection_new ("Please select the image directory."));
1352 fsd = (file_selection_data *) malloc (sizeof (*fsd));
1354 fsd->widget = selector;
1357 if (p->image_directory && *p->image_directory)
1358 gtk_file_selection_set_filename (selector, p->image_directory);
1360 gtk_signal_connect (GTK_OBJECT (selector->ok_button),
1361 "clicked", GTK_SIGNAL_FUNC (browse_image_dir_ok),
1363 gtk_signal_connect (GTK_OBJECT (selector->cancel_button),
1364 "clicked", GTK_SIGNAL_FUNC (browse_image_dir_cancel),
1366 gtk_signal_connect (GTK_OBJECT (selector), "delete_event",
1367 GTK_SIGNAL_FUNC (browse_image_dir_close),
1370 gtk_widget_set_sensitive (GTK_WIDGET (selector->file_list), False);
1372 gtk_window_set_modal (GTK_WINDOW (selector), True);
1373 gtk_widget_show (GTK_WIDGET (selector));
1378 /* Populating the various widgets
1382 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
1385 format_time (char *buf, Time time)
1387 int s = time / 1000;
1388 unsigned int h = 0, m = 0;
1399 sprintf (buf, "%u:%02u:%02u", h, m, s);
1403 /* Finds the number of the last hack to run, and makes that item be
1404 selected by default.
1407 scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
1409 saver_preferences *p = pair->a;
1412 unsigned long nitems, bytesafter;
1414 Display *dpy = GDK_DISPLAY();
1418 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
1419 XA_SCREENSAVER_STATUS,
1420 0, 3, False, XA_INTEGER,
1421 &type, &format, &nitems, &bytesafter,
1422 (unsigned char **) &data)
1424 && type == XA_INTEGER
1427 which = (int) data[2] - 1;
1429 if (data) free (data);
1434 list = GTK_LIST (name_to_widget (toplevel, "list"));
1435 apply_changes_and_save (toplevel);
1436 if (which < p->screenhacks_count)
1438 gtk_list_select_item (list, which);
1439 ensure_selected_item_visible (GTK_WIDGET (list));
1440 populate_demo_window (toplevel, which, pair);
1447 populate_hack_list (GtkWidget *toplevel, prefs_pair *pair)
1449 saver_preferences *p = pair->a;
1450 GtkList *list = GTK_LIST (name_to_widget (toplevel, "list"));
1451 screenhack **hacks = p->screenhacks;
1454 for (h = hacks; h && *h; h++)
1456 /* A GtkList must contain only GtkListItems, but those can contain
1457 an arbitrary widget. We add an Hbox, and inside that, a Checkbox
1458 and a Label. We handle single and double click events on the
1459 line itself, for clicking on the text, but the interior checkbox
1460 also handles its own events.
1463 GtkWidget *line_hbox;
1464 GtkWidget *line_check;
1465 GtkWidget *line_label;
1467 char *pretty_name = (h[0]->name
1468 ? strdup (h[0]->name)
1469 : make_hack_name (h[0]->command));
1471 line = gtk_list_item_new ();
1472 line_hbox = gtk_hbox_new (FALSE, 0);
1473 line_check = gtk_check_button_new ();
1474 line_label = gtk_label_new (pretty_name);
1476 gtk_container_add (GTK_CONTAINER (line), line_hbox);
1477 gtk_box_pack_start (GTK_BOX (line_hbox), line_check, FALSE, FALSE, 0);
1478 gtk_box_pack_start (GTK_BOX (line_hbox), line_label, FALSE, FALSE, 0);
1480 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (line_check),
1482 gtk_label_set_justify (GTK_LABEL (line_label), GTK_JUSTIFY_LEFT);
1484 gtk_widget_show (line_check);
1485 gtk_widget_show (line_label);
1486 gtk_widget_show (line_hbox);
1487 gtk_widget_show (line);
1491 gtk_container_add (GTK_CONTAINER (list), line);
1492 gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
1493 GTK_SIGNAL_FUNC (list_doubleclick_cb),
1496 gtk_signal_connect (GTK_OBJECT (line_check), "toggled",
1497 GTK_SIGNAL_FUNC (list_checkbox_cb),
1501 GTK_WIDGET (GTK_BIN(line)->child)->style =
1502 gtk_style_copy (GTK_WIDGET (text_line)->style);
1504 gtk_widget_show (line);
1507 gtk_signal_connect (GTK_OBJECT (list), "select_child",
1508 GTK_SIGNAL_FUNC (list_select_cb),
1510 gtk_signal_connect (GTK_OBJECT (list), "unselect_child",
1511 GTK_SIGNAL_FUNC (list_unselect_cb),
1517 populate_prefs_page (GtkWidget *top, prefs_pair *pair)
1519 saver_preferences *p = pair->a;
1522 format_time (s, p->timeout);
1523 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "timeout_text")), s);
1524 format_time (s, p->cycle);
1525 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "cycle_text")), s);
1526 format_time (s, p->lock_timeout);
1527 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "lock_text")), s);
1529 format_time (s, p->dpms_standby);
1530 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "dpms_standby_text")),s);
1531 format_time (s, p->dpms_suspend);
1532 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "dpms_suspend_text")),s);
1533 format_time (s, p->dpms_off);
1534 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "dpms_off_text")), s);
1536 format_time (s, p->fade_seconds);
1537 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "fade_text")), s);
1539 gtk_toggle_button_set_active (
1540 GTK_TOGGLE_BUTTON (name_to_widget (top, "lock_button")),
1542 gtk_toggle_button_set_active (
1543 GTK_TOGGLE_BUTTON (name_to_widget (top, "verbose_button")),
1545 gtk_toggle_button_set_active (
1546 GTK_TOGGLE_BUTTON (name_to_widget (top, "capture_button")),
1547 p->capture_stderr_p);
1548 gtk_toggle_button_set_active (
1549 GTK_TOGGLE_BUTTON (name_to_widget (top, "splash_button")),
1552 gtk_toggle_button_set_active (
1553 GTK_TOGGLE_BUTTON (name_to_widget (top, "dpms_button")),
1556 gtk_toggle_button_set_active (
1557 GTK_TOGGLE_BUTTON (name_to_widget (top,"grab_desk_button")),
1559 gtk_toggle_button_set_active (
1560 GTK_TOGGLE_BUTTON (name_to_widget(top,"grab_video_button")),
1562 gtk_toggle_button_set_active (
1563 GTK_TOGGLE_BUTTON (name_to_widget(top,"grab_image_button")),
1565 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "image_text")),
1566 (p->image_directory ? p->image_directory : ""));
1567 gtk_widget_set_sensitive (GTK_WIDGET (name_to_widget (top, "image_text")),
1569 gtk_widget_set_sensitive (
1570 GTK_WIDGET (name_to_widget (top,"image_browse_button")),
1573 gtk_toggle_button_set_active (
1574 GTK_TOGGLE_BUTTON (name_to_widget (top, "install_button")),
1576 gtk_toggle_button_set_active (
1577 GTK_TOGGLE_BUTTON (name_to_widget (top, "fade_button")),
1579 gtk_toggle_button_set_active (
1580 GTK_TOGGLE_BUTTON (name_to_widget (top, "unfade_button")),
1585 Bool found_any_writable_cells = False;
1586 Bool dpms_supported = False;
1588 Display *dpy = GDK_DISPLAY();
1589 int nscreens = ScreenCount(dpy);
1591 for (i = 0; i < nscreens; i++)
1593 Screen *s = ScreenOfDisplay (dpy, i);
1594 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1596 found_any_writable_cells = True;
1601 #ifdef HAVE_XF86VMODE_GAMMA
1602 found_any_writable_cells = True; /* if we can gamma fade, go for it */
1605 #ifdef HAVE_DPMS_EXTENSION
1607 int op = 0, event = 0, error = 0;
1608 if (XQueryExtension (dpy, "DPMS", &op, &event, &error))
1609 dpms_supported = True;
1611 #endif /* HAVE_DPMS_EXTENSION */
1614 /* Blanking and Locking
1616 gtk_widget_set_sensitive (
1617 GTK_WIDGET (name_to_widget (top, "lock_label")),
1619 gtk_widget_set_sensitive (
1620 GTK_WIDGET (name_to_widget (top, "lock_text")),
1625 gtk_widget_set_sensitive (
1626 GTK_WIDGET (name_to_widget (top, "dpms_frame")),
1628 gtk_widget_set_sensitive (
1629 GTK_WIDGET (name_to_widget (top, "dpms_button")),
1631 gtk_widget_set_sensitive (
1632 GTK_WIDGET (name_to_widget (top, "dpms_standby_label")),
1633 dpms_supported && p->dpms_enabled_p);
1634 gtk_widget_set_sensitive (
1635 GTK_WIDGET (name_to_widget (top, "dpms_standby_text")),
1636 dpms_supported && p->dpms_enabled_p);
1637 gtk_widget_set_sensitive (
1638 GTK_WIDGET (name_to_widget (top, "dpms_suspend_label")),
1639 dpms_supported && p->dpms_enabled_p);
1640 gtk_widget_set_sensitive (
1641 GTK_WIDGET (name_to_widget (top, "dpms_suspend_text")),
1642 dpms_supported && p->dpms_enabled_p);
1643 gtk_widget_set_sensitive (
1644 GTK_WIDGET (name_to_widget (top, "dpms_off_label")),
1645 dpms_supported && p->dpms_enabled_p);
1646 gtk_widget_set_sensitive (
1647 GTK_WIDGET (name_to_widget (top, "dpms_off_text")),
1648 dpms_supported && p->dpms_enabled_p);
1652 gtk_widget_set_sensitive (
1653 GTK_WIDGET (name_to_widget (top, "cmap_frame")),
1654 found_any_writable_cells);
1655 gtk_widget_set_sensitive (
1656 GTK_WIDGET (name_to_widget (top, "install_button")),
1657 found_any_writable_cells);
1658 gtk_widget_set_sensitive (
1659 GTK_WIDGET (name_to_widget (top, "fade_button")),
1660 found_any_writable_cells);
1661 gtk_widget_set_sensitive (
1662 GTK_WIDGET (name_to_widget (top, "unfade_button")),
1663 found_any_writable_cells);
1665 gtk_widget_set_sensitive (
1666 GTK_WIDGET (name_to_widget (top, "fade_label")),
1667 (found_any_writable_cells &&
1668 (p->fade_p || p->unfade_p)));
1669 gtk_widget_set_sensitive (
1670 GTK_WIDGET (name_to_widget (top, "fade_text")),
1671 (found_any_writable_cells &&
1672 (p->fade_p || p->unfade_p)));
1679 sensitize_demo_widgets (GtkWidget *toplevel, Bool sensitive_p)
1681 const char *names[] = { "cmd_label", "cmd_text", "enabled",
1682 "visual", "visual_combo",
1685 for (i = 0; i < countof(names); i++)
1687 GtkWidget *w = name_to_widget (toplevel, names[i]);
1688 gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
1691 /* I don't know how to handle these yet... */
1693 const char *names2[] = { "cut_menu", "copy_menu", "paste_menu" };
1694 for (i = 0; i < countof(names2); i++)
1696 GtkWidget *w = name_to_widget (toplevel, names2[i]);
1697 gtk_widget_set_sensitive (GTK_WIDGET(w), False);
1703 /* Even though we've given these text fields a maximum number of characters,
1704 their default size is still about 30 characters wide -- so measure out
1705 a string in their font, and resize them to just fit that.
1708 fix_text_entry_sizes (GtkWidget *toplevel)
1710 const char *names[] = { "timeout_text", "cycle_text", "lock_text",
1711 "dpms_standby_text", "dpms_suspend_text",
1712 "dpms_off_text", "fade_text" };
1717 for (i = 0; i < countof(names); i++)
1719 w = GTK_WIDGET (name_to_widget (toplevel, names[i]));
1721 width = gdk_text_width (w->style->font, "00:00:00_", 9);
1722 gtk_widget_set_usize (w, width, -2);
1725 /* Now fix the size of the combo box.
1727 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "visual_combo"));
1728 w = GTK_COMBO (w)->entry;
1729 width = gdk_text_width (w->style->font, "PseudoColor___", 14);
1730 gtk_widget_set_usize (w, width, -2);
1732 /* Now fix the size of the file entry text.
1734 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "image_text"));
1735 width = gdk_text_width (w->style->font, "MMMMMMMMMMMMMM", 14);
1736 gtk_widget_set_usize (w, width, -2);
1739 /* Now fix the size of the list.
1741 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "list"));
1742 width = gdk_text_width (w->style->font, "nnnnnnnnnnnnnnnnnnnnnn", 22);
1743 gtk_widget_set_usize (w, width, -2);
1750 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...)
1753 static char *up_arrow_xpm[] = {
1776 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1777 the end of the array (Gtk 1.2.5.) */
1778 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1779 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1782 static char *down_arrow_xpm[] = {
1805 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1806 the end of the array (Gtk 1.2.5.) */
1807 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1808 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1812 pixmapify_button (GtkWidget *toplevel, int down_p)
1816 GtkWidget *pixmapwid;
1820 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel),
1821 (down_p ? "next" : "prev")));
1822 style = gtk_widget_get_style (w);
1824 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1825 &style->bg[GTK_STATE_NORMAL],
1827 ? (gchar **) down_arrow_xpm
1828 : (gchar **) up_arrow_xpm));
1829 pixmapwid = gtk_pixmap_new (pixmap, mask);
1830 gtk_widget_show (pixmapwid);
1831 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1832 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1836 map_next_button_cb (GtkWidget *w, gpointer user_data)
1838 pixmapify_button (w, 1);
1842 map_prev_button_cb (GtkWidget *w, gpointer user_data)
1844 pixmapify_button (w, 0);
1849 /* Work around a Gtk bug that causes label widgets to wrap text too early.
1853 you_are_not_a_unique_or_beautiful_snowflake (GtkWidget *label,
1854 GtkAllocation *allocation,
1858 GtkWidgetAuxInfo *aux_info;
1860 aux_info = gtk_object_get_data (GTK_OBJECT (label), "gtk-aux-info");
1862 aux_info->width = allocation->width;
1863 aux_info->height = -2;
1867 gtk_widget_size_request (label, &req);
1871 /* Feel the love. Thanks to Nat Friedman for finding this workaround.
1874 eschew_gtk_lossage (GtkWidget *toplevel)
1876 GtkWidgetAuxInfo *aux_info;
1877 GtkWidget *label = GTK_WIDGET (name_to_widget (toplevel, "doc"));
1879 aux_info = g_new0 (GtkWidgetAuxInfo, 1);
1880 aux_info->width = label->allocation.width;
1881 aux_info->height = -2;
1885 gtk_object_set_data (GTK_OBJECT (label), "gtk-aux-info", aux_info);
1887 gtk_signal_connect (GTK_OBJECT (label), "size_allocate",
1888 you_are_not_a_unique_or_beautiful_snowflake, NULL);
1890 gtk_widget_queue_resize (label);
1895 get_hack_blurb (screenhack *hack)
1898 char *prog_name = strdup (hack->command);
1899 char *pretty_name = (hack->name
1900 ? strdup (hack->name)
1901 : make_hack_name (hack->command));
1902 char doc_name[255], doc_class[255];
1905 for (s = prog_name; *s && !isspace(*s); s++)
1908 s = strrchr (prog_name, '/');
1909 if (s) strcpy (prog_name, s+1);
1911 sprintf (doc_name, "hacks.%s.documentation", pretty_name);
1912 sprintf (doc_class, "hacks.%s.documentation", prog_name);
1916 doc_string = get_string_resource (doc_name, doc_class);
1919 for (s = doc_string; *s; s++)
1923 /* skip over whitespace at beginning of line */
1925 while (*s && (*s == ' ' || *s == '\t'))
1928 else if (*s == ' ' || *s == '\t')
1930 /* compress all other horizontal whitespace. */
1933 for (s2 = s; *s2 && (*s2 == ' ' || *s2 == '\t'); s2++)
1935 if (s2 > s) strcpy (s, s2);
1940 while (*s && isspace (*s)) /* Strip trailing whitespace */
1943 /* Delete whitespace at end of each line. */
1944 for (; s > doc_string; s--)
1945 if (*s == '\n' && (s[-1] == ' ' || s[-1] == '\t'))
1948 s2 > doc_string && (*s2 == ' ' || *s2 == '\t');
1952 if (s2 < s) strcpy (s2, s);
1956 /* Delete leading blank lines. */
1957 for (s = doc_string; *s == '\n'; s++)
1959 if (s > doc_string) strcpy (doc_string, s);
1963 static int doc_installed = 0;
1964 if (doc_installed == 0)
1966 if (get_boolean_resource ("hacks.documentation.isInstalled",
1967 "hacks.documentation.isInstalled"))
1973 if (doc_installed < 0)
1975 strdup ("Error:\n\n"
1976 "The documentation strings do not appear to be "
1977 "installed. This is probably because there is "
1978 "an \"XScreenSaver\" app-defaults file installed "
1979 "that is from an older version of the program. "
1980 "To fix this problem, delete that file, or "
1981 "install a current version (either will work.)");
1983 doc_string = strdup ("");
1991 populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
1993 saver_preferences *p = pair->a;
1994 screenhack *hack = (which >= 0 && which < p->screenhacks_count
1995 ? p->screenhacks[which] : 0);
1996 GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
1997 GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
1998 GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
1999 GtkToggleButton *enabled =
2000 GTK_TOGGLE_BUTTON (name_to_widget (toplevel, "enabled"));
2001 GtkCombo *vis = GTK_COMBO (name_to_widget (toplevel, "visual_combo"));
2003 char *pretty_name = (hack
2005 ? strdup (hack->name)
2006 : make_hack_name (hack->command))
2008 char *doc_string = hack ? get_hack_blurb (hack) : 0;
2010 gtk_frame_set_label (frame, (pretty_name ? pretty_name : ""));
2011 gtk_label_set_text (doc, (doc_string ? doc_string : ""));
2012 gtk_entry_set_text (cmd, (hack ? hack->command : ""));
2013 gtk_entry_set_position (cmd, 0);
2015 updating_enabled_cb++;
2016 gtk_toggle_button_set_active (enabled, (hack ? hack->enabled_p : False));
2017 updating_enabled_cb--;
2019 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry),
2021 ? (hack->visual && *hack->visual
2026 gtk_container_resize_children (GTK_CONTAINER (GTK_WIDGET (doc)->parent));
2028 sensitize_demo_widgets (toplevel, (hack ? True : False));
2030 if (pretty_name) free (pretty_name);
2031 if (doc_string) free (doc_string);
2033 _selected_hack_number = which;
2038 widget_deleter (GtkWidget *widget, gpointer data)
2040 /* #### Well, I want to destroy these widgets, but if I do that, they get
2041 referenced again, and eventually I get a SEGV. So instead of
2042 destroying them, I'll just hide them, and leak a bunch of memory
2043 every time the disk file changes. Go go go Gtk!
2045 #### Ok, that's a lie, I get a crash even if I just hide the widget
2046 and don't ever delete it. Fuck!
2049 gtk_widget_destroy (widget);
2051 gtk_widget_hide (widget);
2057 maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair)
2060 saver_preferences *p = pair->a;
2062 static Bool reentrant_lock = False;
2063 if (reentrant_lock) return 0;
2064 reentrant_lock = True;
2066 if (init_file_changed_p (p))
2068 const char *f = init_file_name();
2073 if (!f || !*f) return 0;
2074 b = (char *) malloc (strlen(f) + 1024);
2077 "file \"%s\" has changed, reloading.\n",
2079 warning_dialog (widget, b, False, 100);
2084 which = selected_hack_number (widget);
2085 list = GTK_LIST (name_to_widget (widget, "list"));
2086 gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL);
2087 populate_hack_list (widget, pair);
2088 gtk_list_select_item (list, which);
2089 populate_prefs_page (widget, pair);
2090 populate_demo_window (widget, which, pair);
2091 ensure_selected_item_visible (GTK_WIDGET (list));
2096 reentrant_lock = False;
2102 /* Setting window manager icon
2106 init_icon (GdkWindow *window)
2108 GdkBitmap *mask = 0;
2111 gdk_pixmap_create_from_xpm_d (window, &mask, &transp,
2112 (gchar **) logo_50_xpm);
2114 gdk_window_set_icon (window, 0, pixmap, mask);
2118 /* The main demo-mode command loop.
2123 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
2124 XrmRepresentation *type, XrmValue *value, XPointer closure)
2127 for (i = 0; quarks[i]; i++)
2129 if (bindings[i] == XrmBindTightly)
2130 fprintf (stderr, (i == 0 ? "" : "."));
2131 else if (bindings[i] == XrmBindLoosely)
2132 fprintf (stderr, "*");
2134 fprintf (stderr, " ??? ");
2135 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
2138 fprintf (stderr, ": %s\n", (char *) value->addr);
2146 the_network_is_not_the_computer (GtkWidget *parent)
2148 Display *dpy = GDK_DISPLAY();
2149 char *rversion, *ruser, *rhost;
2150 char *luser, *lhost;
2152 struct passwd *p = getpwuid (getuid ());
2153 const char *d = DisplayString (dpy);
2155 # if defined(HAVE_UNAME)
2157 if (uname (&uts) < 0)
2158 lhost = "<UNKNOWN>";
2160 lhost = uts.nodename;
2162 strcpy (lhost, getenv("SYS$NODE"));
2163 # else /* !HAVE_UNAME && !VMS */
2164 strcat (lhost, "<UNKNOWN>");
2165 # endif /* !HAVE_UNAME && !VMS */
2167 if (p && p->pw_name)
2172 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
2174 /* Make a buffer that's big enough for a number of copies of all the
2175 strings, plus some. */
2176 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
2177 (ruser ? strlen(ruser) : 0) +
2178 (rhost ? strlen(rhost) : 0) +
2185 if (!rversion || !*rversion)
2189 "The XScreenSaver daemon doesn't seem to be running\n"
2190 "on display \"%s\". Launch it now?",
2193 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
2195 /* Warn that the two processes are running as different users.
2199 "%s is running as user \"%s\" on host \"%s\".\n"
2200 "But the xscreensaver managing display \"%s\"\n"
2201 "is running as user \"%s\" on host \"%s\".\n"
2203 "Since they are different users, they won't be reading/writing\n"
2204 "the same ~/.xscreensaver file, so %s isn't\n"
2205 "going to work right.\n"
2207 "You should either re-run %s as \"%s\", or re-run\n"
2208 "xscreensaver as \"%s\".\n"
2210 "Restart the xscreensaver daemon now?\n",
2211 progname, luser, lhost,
2213 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
2215 progname, (ruser ? ruser : "???"),
2218 else if (rhost && *rhost && !!strcmp (rhost, lhost))
2220 /* Warn that the two processes are running on different hosts.
2224 "%s is running as user \"%s\" on host \"%s\".\n"
2225 "But the xscreensaver managing display \"%s\"\n"
2226 "is running as user \"%s\" on host \"%s\".\n"
2228 "If those two machines don't share a file system (that is,\n"
2229 "if they don't see the same ~%s/.xscreensaver file) then\n"
2230 "%s won't work right.\n"
2232 "Restart the daemon on \"%s\" as \"%s\" now?\n",
2233 progname, luser, lhost,
2235 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
2240 else if (!!strcmp (rversion, short_version))
2242 /* Warn that the version numbers don't match.
2246 "This is %s version %s.\n"
2247 "But the xscreensaver managing display \"%s\"\n"
2248 "is version %s. This could cause problems.\n"
2250 "Restart the xscreensaver daemon now?\n",
2251 progname, short_version,
2258 warning_dialog (parent, msg, True, 1);
2264 /* We use this error handler so that X errors are preceeded by the name
2265 of the program that generated them.
2268 demo_ehandler (Display *dpy, XErrorEvent *error)
2270 fprintf (stderr, "\nX error in %s:\n", progname);
2271 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
2274 fprintf (stderr, " (nonfatal.)\n");
2279 /* We use this error handler so that Gtk/Gdk errors are preceeded by the name
2280 of the program that generated them; and also that we can ignore one
2281 particular bogus error message that Gdk madly spews.
2284 g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
2285 const gchar *message, gpointer user_data)
2287 /* Ignore the message "Got event for unknown window: 0x...".
2288 Apparently some events are coming in for the xscreensaver window
2289 (presumably reply events related to the ClientMessage) and Gdk
2290 feels the need to complain about them. So, just suppress any
2291 messages that look like that one.
2293 if (strstr (message, "unknown window"))
2296 fprintf (stderr, "%s: %s-%s: %s%s", blurb(), log_domain,
2297 (log_level == G_LOG_LEVEL_ERROR ? "error" :
2298 log_level == G_LOG_LEVEL_CRITICAL ? "critical" :
2299 log_level == G_LOG_LEVEL_WARNING ? "warning" :
2300 log_level == G_LOG_LEVEL_MESSAGE ? "message" :
2301 log_level == G_LOG_LEVEL_INFO ? "info" :
2302 log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"),
2304 ((!*message || message[strlen(message)-1] != '\n')
2309 static char *defaults[] = {
2310 #include "XScreenSaver_ad.h"
2315 #ifdef HAVE_CRAPPLET
2316 static struct poptOption crapplet_options[] = {
2317 {NULL, '\0', 0, NULL, 0}
2319 #endif /* HAVE_CRAPPLET */
2323 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n", \
2328 map_window_cb (GtkWidget *w, gpointer user_data)
2330 Boolean oi = initializing_p;
2331 initializing_p = True;
2332 eschew_gtk_lossage (w);
2333 ensure_selected_item_visible (GTK_WIDGET(name_to_widget(w, "list")));
2334 initializing_p = oi;
2339 main (int argc, char **argv)
2342 prefs_pair Pair, *pair;
2343 saver_preferences P, P2, *p, *p2;
2347 Widget toplevel_shell;
2348 GtkWidget *gtk_window;
2349 char *real_progname = argv[0];
2352 initializing_p = True;
2354 s = strrchr (real_progname, '/');
2355 if (s) real_progname = s+1;
2362 memset (p, 0, sizeof (*p));
2363 memset (p2, 0, sizeof (*p2));
2365 global_prefs_pair = pair; /* I hate C so much... */
2367 progname = real_progname;
2369 short_version = (char *) malloc (5);
2370 memcpy (short_version, screensaver_id + 17, 4);
2371 short_version [4] = 0;
2374 /* Register our error message logger for every ``log domain'' known.
2375 There's no way to do this globally, so I grepped the Gtk/Gdk sources
2376 for all of the domains that seem to be in use.
2379 const char * const domains[] = { "Gtk", "Gdk", "GLib", "GModule",
2380 "GThread", "Gnome", "GnomeUI", 0 };
2381 for (i = 0; domains[i]; i++)
2382 g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0);
2385 /* This is gross, but Gtk understands --display and not -display...
2387 for (i = 1; i < argc; i++)
2388 if (argv[i][0] && argv[i][1] &&
2389 !strncmp(argv[i], "-display", strlen(argv[i])))
2390 argv[i] = "--display";
2393 /* We need to parse this arg really early... Sigh. */
2394 for (i = 1; i < argc; i++)
2396 (!strcmp(argv[i], "--crapplet") ||
2397 !strcmp(argv[i], "--capplet")))
2399 # ifdef HAVE_CRAPPLET
2402 for (j = i; j < argc; j++) /* remove it from the list */
2403 argv[j] = argv[j+1];
2406 # else /* !HAVE_CRAPPLET */
2407 fprintf (stderr, "%s: not compiled with --crapplet support\n",
2411 # endif /* !HAVE_CRAPPLET */
2414 /* Let Gtk open the X connection, then initialize Xt to use that
2415 same connection. Doctor Frankenstein would be proud.
2417 # ifdef HAVE_CRAPPLET
2420 GnomeClient *client;
2421 GnomeClientFlags flags = 0;
2423 int init_results = gnome_capplet_init ("screensaver-properties",
2425 argc, argv, NULL, 0, NULL);
2427 0 upon successful initialization;
2428 1 if --init-session-settings was passed on the cmdline;
2429 2 if --ignore was passed on the cmdline;
2432 So the 1 signifies just to init the settings, and quit, basically.
2433 (Meaning launch the xscreensaver daemon.)
2436 if (init_results < 0)
2439 g_error ("An initialization error occurred while "
2440 "starting xscreensaver-capplet.\n");
2442 fprintf (stderr, "%s: gnome_capplet_init failed: %d\n",
2443 real_progname, init_results);
2448 client = gnome_master_client ();
2451 flags = gnome_client_get_flags (client);
2453 if (flags & GNOME_CLIENT_IS_CONNECTED)
2456 gnome_startup_acquire_token ("GNOME_SCREENSAVER_PROPERTIES",
2457 gnome_client_get_id (client));
2460 char *session_args[20];
2462 session_args[i++] = real_progname;
2463 session_args[i++] = "--capplet";
2464 session_args[i++] = "--init-session-settings";
2465 session_args[i] = 0;
2466 gnome_client_set_priority (client, 20);
2467 gnome_client_set_restart_style (client, GNOME_RESTART_ANYWAY);
2468 gnome_client_set_restart_command (client, i, session_args);
2472 gnome_client_set_restart_style (client, GNOME_RESTART_NEVER);
2475 gnome_client_flush (client);
2478 if (init_results == 1)
2480 system ("xscreensaver -nosplash &");
2486 # endif /* HAVE_CRAPPLET */
2488 gtk_init (&argc, &argv);
2492 /* We must read exactly the same resources as xscreensaver.
2493 That means we must have both the same progclass *and* progname,
2494 at least as far as the resource database is concerned. So,
2495 put "xscreensaver" in argv[0] while initializing Xt.
2497 argv[0] = "xscreensaver";
2501 /* Teach Xt to use the Display that Gtk/Gdk have already opened.
2503 XtToolkitInitialize ();
2504 app = XtCreateApplicationContext ();
2505 dpy = GDK_DISPLAY();
2506 XtAppSetFallbackResources (app, defaults);
2507 XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv);
2508 toplevel_shell = XtAppCreateShell (progname, progclass,
2509 applicationShellWidgetClass,
2512 dpy = XtDisplay (toplevel_shell);
2513 db = XtDatabase (dpy);
2514 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
2515 XSetErrorHandler (demo_ehandler);
2518 /* After doing Xt-style command-line processing, complain about any
2519 unrecognized command-line arguments.
2521 for (i = 1; i < argc; i++)
2524 if (s[0] == '-' && s[1] == '-')
2526 if (!strcmp (s, "-prefs"))
2528 else if (crapplet_p)
2529 /* There are lots of random args that we don't care about when we're
2530 started as a crapplet, so just ignore unknown args in that case. */
2534 fprintf (stderr, "%s: unknown option: %s\n", real_progname, argv[i]);
2540 /* Load the init file, which may end up consulting the X resource database
2541 and the site-wide app-defaults file. Note that at this point, it's
2542 important that `progname' be "xscreensaver", rather than whatever
2549 /* Now that Xt has been initialized, and the resources have been read,
2550 we can set our `progname' variable to something more in line with
2553 progname = real_progname;
2557 /* Print out all the resources we read. */
2559 XrmName name = { 0 };
2560 XrmClass class = { 0 };
2562 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
2568 /* Intern the atoms that xscreensaver_command() needs.
2570 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
2571 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
2572 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
2573 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
2574 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
2575 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
2576 XA_SELECT = XInternAtom (dpy, "SELECT", False);
2577 XA_DEMO = XInternAtom (dpy, "DEMO", False);
2578 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
2579 XA_BLANK = XInternAtom (dpy, "BLANK", False);
2580 XA_LOCK = XInternAtom (dpy, "LOCK", False);
2581 XA_EXIT = XInternAtom (dpy, "EXIT", False);
2582 XA_RESTART = XInternAtom (dpy, "RESTART", False);
2585 /* Create the window and all its widgets.
2587 gtk_window = create_xscreensaver_demo ();
2588 toplevel_widget = gtk_window;
2590 /* Set the window's title. */
2593 char *v = (char *) strdup(strchr(screensaver_id, ' '));
2594 char *s1, *s2, *s3, *s4;
2595 s1 = (char *) strchr(v, ' '); s1++;
2596 s2 = (char *) strchr(s1, ' ');
2597 s3 = (char *) strchr(v, '('); s3++;
2598 s4 = (char *) strchr(s3, ')');
2601 sprintf (title, "%.50s %.50s, %.50s", progclass, s1, s3);
2602 gtk_window_set_title (GTK_WINDOW (gtk_window), title);
2606 /* Various other widget initializations...
2608 gtk_signal_connect (GTK_OBJECT (gtk_window), "delete_event",
2609 GTK_SIGNAL_FUNC (wm_close_cb), NULL);
2611 populate_hack_list (gtk_window, pair);
2612 populate_prefs_page (gtk_window, pair);
2613 sensitize_demo_widgets (gtk_window, False);
2614 fix_text_entry_sizes (gtk_window);
2615 scroll_to_current_hack (gtk_window, pair);
2617 gtk_signal_connect (
2618 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "list")),
2619 "map", GTK_SIGNAL_FUNC(map_window_cb), 0);
2620 gtk_signal_connect (
2621 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "prev")),
2622 "map", GTK_SIGNAL_FUNC(map_prev_button_cb), 0);
2623 gtk_signal_connect (
2624 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "next")),
2625 "map", GTK_SIGNAL_FUNC(map_next_button_cb), 0);
2628 /* Handle the -prefs command-line argument. */
2631 GtkNotebook *notebook =
2632 GTK_NOTEBOOK (name_to_widget (gtk_window, "notebook"));
2633 gtk_notebook_set_page (notebook, 1);
2636 # ifdef HAVE_CRAPPLET
2640 GtkWidget *top_vbox;
2642 capplet = capplet_widget_new ();
2644 top_vbox = GTK_BIN (gtk_window)->child;
2646 gtk_widget_ref (top_vbox);
2647 gtk_container_remove (GTK_CONTAINER (gtk_window), top_vbox);
2648 GTK_OBJECT_SET_FLAGS (top_vbox, GTK_FLOATING);
2650 /* In crapplet-mode, take off the menubar. */
2651 gtk_widget_hide (name_to_widget (gtk_window, "menubar"));
2653 gtk_container_add (GTK_CONTAINER (capplet), top_vbox);
2654 gtk_widget_show (capplet);
2655 gtk_widget_hide (gtk_window);
2657 /* Hook up the Control Center's redundant Help button, too. */
2658 gtk_signal_connect (GTK_OBJECT (capplet), "help",
2659 GTK_SIGNAL_FUNC (doc_menu_cb), 0);
2661 /* Issue any warnings about the running xscreensaver daemon. */
2662 the_network_is_not_the_computer (top_vbox);
2665 # endif /* HAVE_CRAPPLET */
2667 gtk_widget_show (gtk_window);
2668 init_icon (GTK_WIDGET(gtk_window)->window);
2670 /* Issue any warnings about the running xscreensaver daemon. */
2671 the_network_is_not_the_computer (gtk_window);
2674 /* Run the Gtk event loop, and not the Xt event loop. This means that
2675 if there were Xt timers or fds registered, they would never get serviced,
2676 and if there were any Xt widgets, they would never have events delivered.
2677 Fortunately, we're using Gtk for all of the UI, and only initialized
2678 Xt so that we could process the command line and use the X resource
2681 initializing_p = False;
2683 # ifdef HAVE_CRAPPLET
2685 capplet_gtk_main ();
2687 # endif /* HAVE_CRAPPLET */
2693 #endif /* HAVE_GTK -- whole file */