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>
65 extern Display *gdk_display;
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;
259 char *s = strchr (head, '\n');
262 sprintf (name, "label%d", i++);
265 label = gtk_label_new (head);
269 GTK_WIDGET (label)->style =
270 gtk_style_copy (GTK_WIDGET (label)->style);
271 GTK_WIDGET (label)->style->font =
272 gdk_font_load (get_string_resource("warning_dialog.headingFont",
274 gtk_widget_set_style (GTK_WIDGET (label),
275 GTK_WIDGET (label)->style);
279 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
280 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
281 label, TRUE, TRUE, 0);
282 gtk_widget_show (label);
293 label = gtk_label_new ("");
294 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
295 label, TRUE, TRUE, 0);
296 gtk_widget_show (label);
298 label = gtk_hbutton_box_new ();
299 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
300 label, TRUE, TRUE, 0);
302 ok = gtk_button_new_with_label ("OK");
303 gtk_container_add (GTK_CONTAINER (label), ok);
305 if (restart_button_p)
307 cancel = gtk_button_new_with_label ("Cancel");
308 gtk_container_add (GTK_CONTAINER (label), cancel);
311 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
312 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
313 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
314 gtk_widget_show (ok);
316 gtk_widget_show (cancel);
317 gtk_widget_show (label);
318 gtk_widget_show (dialog);
319 /* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
321 if (restart_button_p)
323 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
324 GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
326 gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
327 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
332 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
333 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
336 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
337 GTK_WIDGET (parent)->window);
339 gdk_window_show (GTK_WIDGET (dialog)->window);
340 gdk_window_raise (GTK_WIDGET (dialog)->window);
347 run_cmd (GtkWidget *widget, Atom command, int arg)
352 apply_changes_and_save (widget);
353 status = xscreensaver_command (gdk_display, command, arg, False, &err);
358 sprintf (buf, "Error:\n\n%s", err);
360 strcpy (buf, "Unknown error!");
361 warning_dialog (widget, buf, False, 100);
368 run_hack (GtkWidget *widget, int which, Bool report_errors_p)
370 if (which < 0) return;
371 apply_changes_and_save (widget);
373 run_cmd (widget, XA_DEMO, which + 1);
377 xscreensaver_command (gdk_display, XA_DEMO, which + 1, False, &s);
388 exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
390 apply_changes_and_save (GTK_WIDGET (menuitem));
395 wm_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
397 apply_changes_and_save (widget);
403 cut_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
406 warning_dialog (GTK_WIDGET (menuitem),
408 "cut unimplemented\n", False, 1);
413 copy_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
416 warning_dialog (GTK_WIDGET (menuitem),
418 "copy unimplemented\n", False, 1);
423 paste_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
426 warning_dialog (GTK_WIDGET (menuitem),
428 "paste unimplemented\n", False, 1);
433 about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
436 char *vers = strdup (screensaver_id + 4);
439 char *desc = "For updates, check http://www.jwz.org/xscreensaver/";
441 s = strchr (vers, ',');
445 sprintf(copy, "Copyright \251 1991-2001 %s", s);
447 sprintf (msg, "%s\n\n%s", copy, desc);
449 /* I can't make gnome_about_new() work here -- it starts dying in
450 gdk_imlib_get_visual() under gnome_about_new(). If this worked,
451 then this might be the thing to do:
455 const gchar *auth[] = { 0 };
456 GtkWidget *about = gnome_about_new (progclass, vers, "", auth, desc,
458 gtk_widget_show (about);
460 #else / * GTK but not GNOME * /
464 GdkColormap *colormap;
465 GdkPixmap *gdkpixmap;
468 GtkWidget *dialog = gtk_dialog_new ();
469 GtkWidget *hbox, *icon, *vbox, *label1, *label2, *hb, *ok;
470 GtkWidget *parent = GTK_WIDGET (menuitem);
471 while (parent->parent)
472 parent = parent->parent;
474 hbox = gtk_hbox_new (FALSE, 20);
475 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
476 hbox, TRUE, TRUE, 0);
478 colormap = gtk_widget_get_colormap (parent);
480 gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, NULL,
481 (gchar **) logo_180_xpm);
482 icon = gtk_pixmap_new (gdkpixmap, mask);
483 gtk_misc_set_padding (GTK_MISC (icon), 10, 10);
485 gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
487 vbox = gtk_vbox_new (FALSE, 0);
488 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
490 label1 = gtk_label_new (vers);
491 gtk_box_pack_start (GTK_BOX (vbox), label1, TRUE, TRUE, 0);
492 gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT);
493 gtk_misc_set_alignment (GTK_MISC (label1), 0.0, 0.75);
495 GTK_WIDGET (label1)->style = gtk_style_copy (GTK_WIDGET (label1)->style);
496 GTK_WIDGET (label1)->style->font =
497 gdk_font_load (get_string_resource ("about.headingFont","Dialog.Font"));
498 gtk_widget_set_style (GTK_WIDGET (label1), GTK_WIDGET (label1)->style);
500 label2 = gtk_label_new (msg);
501 gtk_box_pack_start (GTK_BOX (vbox), label2, TRUE, TRUE, 0);
502 gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
503 gtk_misc_set_alignment (GTK_MISC (label2), 0.0, 0.25);
505 GTK_WIDGET (label2)->style = gtk_style_copy (GTK_WIDGET (label2)->style);
506 GTK_WIDGET (label2)->style->font =
507 gdk_font_load (get_string_resource ("about.bodyFont","Dialog.Font"));
508 gtk_widget_set_style (GTK_WIDGET (label2), GTK_WIDGET (label2)->style);
510 hb = gtk_hbutton_box_new ();
512 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
515 ok = gtk_button_new_with_label ("OK");
516 gtk_container_add (GTK_CONTAINER (hb), ok);
518 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
519 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
520 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
522 gtk_widget_show (hbox);
523 gtk_widget_show (icon);
524 gtk_widget_show (vbox);
525 gtk_widget_show (label1);
526 gtk_widget_show (label2);
527 gtk_widget_show (hb);
528 gtk_widget_show (ok);
529 gtk_widget_show (dialog);
531 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
532 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
534 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
535 GTK_WIDGET (parent)->window);
536 gdk_window_show (GTK_WIDGET (dialog)->window);
537 gdk_window_raise (GTK_WIDGET (dialog)->window);
543 doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
545 /* prefs_pair *pair = (prefs_pair *) client_data; */
546 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
548 saver_preferences *p = pair->a;
551 if (!p->help_url || !*p->help_url)
553 warning_dialog (GTK_WIDGET (menuitem),
555 "No Help URL has been specified.\n", False, 100);
559 help_command = (char *) malloc (strlen (p->load_url_command) +
560 (strlen (p->help_url) * 2) + 20);
561 strcpy (help_command, "( ");
562 sprintf (help_command + strlen(help_command),
563 p->load_url_command, p->help_url, p->help_url);
564 strcat (help_command, " ) &");
565 system (help_command);
571 activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
573 run_cmd (GTK_WIDGET (menuitem), XA_ACTIVATE, 0);
578 lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
580 run_cmd (GTK_WIDGET (menuitem), XA_LOCK, 0);
585 kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
587 run_cmd (GTK_WIDGET (menuitem), XA_EXIT, 0);
592 restart_menu_cb (GtkWidget *widget, gpointer user_data)
595 run_cmd (GTK_WIDGET (widget), XA_RESTART, 0);
597 apply_changes_and_save (GTK_WIDGET (widget));
598 xscreensaver_command (gdk_display, XA_EXIT, 0, False, NULL);
600 system ("xscreensaver -nosplash &");
603 await_xscreensaver (GTK_WIDGET (widget));
607 await_xscreensaver (GtkWidget *widget)
611 Display *dpy = gdk_display;
612 /* GtkWidget *dialog = 0;*/
615 while (!rversion && (--countdown > 0))
617 /* Check for the version of the running xscreensaver... */
618 server_xscreensaver_version (dpy, &rversion, 0, 0);
620 /* If it's not there yet, wait a second... */
624 /* if (dialog) gtk_widget_destroy (dialog);*/
633 /* Timed out, no screensaver running. */
636 Bool root_p = (geteuid () == 0);
640 "The xscreensaver daemon did not start up properly.\n"
645 "You are running as root. This usually means that xscreensaver\n"
646 "was unable to contact your X server because access control is\n"
647 "turned on. Try running this command:\n"
649 " xhost +localhost\n"
651 "and then selecting `File / Restart Daemon'.\n"
653 "Note that turning off access control will allow anyone logged\n"
654 "on to this machine to access your screen, which might be\n"
655 "considered a security problem. Please read the xscreensaver\n"
656 "manual and FAQ for more information.\n"
658 "You shouldn't run X as root. Instead, you should log in as a\n"
659 "normal user, and `su' as necessary.");
661 strcat (buf, "Please check your $PATH and permissions.");
663 warning_dialog (widget, buf, False, 1);
668 static int _selected_hack_number = -1;
671 selected_hack_number (GtkWidget *toplevel)
674 GtkViewport *vp = GTK_VIEWPORT (name_to_widget (toplevel, "viewport"));
675 GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
676 GList *slist = list_widget->selection;
677 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
678 int which = (selected
679 ? gtk_list_child_position (list_widget, GTK_WIDGET (selected))
683 return _selected_hack_number;
689 demo_write_init_file (GtkWidget *widget, saver_preferences *p)
691 if (!write_init_file (p, short_version, False))
695 const char *f = init_file_name();
697 warning_dialog (widget,
698 "Error:\n\nCouldn't determine init file name!\n",
702 char *b = (char *) malloc (strlen(f) + 1024);
703 sprintf (b, "Error:\n\nCouldn't write %s\n", f);
704 warning_dialog (widget, b, False, 100);
713 apply_changes_and_save_1 (GtkWidget *widget)
715 /* prefs_pair *pair = (prefs_pair *) client_data; */
716 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
717 saver_preferences *p = pair->a;
718 GtkList *list_widget =
719 GTK_LIST (name_to_widget (widget, "list"));
720 int which = selected_hack_number (widget);
722 GtkEntry *cmd = GTK_ENTRY (name_to_widget (widget, "cmd_text"));
723 GtkToggleButton *enabled =
724 GTK_TOGGLE_BUTTON (name_to_widget (widget, "enabled"));
725 GtkCombo *vis = GTK_COMBO (name_to_widget (widget, "visual_combo"));
727 Bool enabled_p = gtk_toggle_button_get_active (enabled);
728 const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
729 const char *command = gtk_entry_get_text (cmd);
734 if (which < 0) return -1;
736 if (maybe_reload_init_file (widget, pair) != 0)
739 /* Sanity-check and canonicalize whatever the user typed into the combo box.
741 if (!strcasecmp (visual, "")) visual = "";
742 else if (!strcasecmp (visual, "any")) visual = "";
743 else if (!strcasecmp (visual, "default")) visual = "Default";
744 else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
745 else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
746 else if (!strcasecmp (visual, "best")) visual = "Best";
747 else if (!strcasecmp (visual, "mono")) visual = "Mono";
748 else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
749 else if (!strcasecmp (visual, "gray")) visual = "Gray";
750 else if (!strcasecmp (visual, "grey")) visual = "Gray";
751 else if (!strcasecmp (visual, "color")) visual = "Color";
752 else if (!strcasecmp (visual, "gl")) visual = "GL";
753 else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
754 else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
755 else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
756 else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
757 else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
758 else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
759 else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
760 else if (1 == sscanf (visual, " %ld %c", &id, &c)) ;
761 else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
764 gdk_beep (); /* unparsable */
766 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");
769 ensure_selected_item_visible (GTK_WIDGET (list_widget));
771 if (!p->screenhacks[which]->visual)
772 p->screenhacks[which]->visual = strdup ("");
773 if (!p->screenhacks[which]->command)
774 p->screenhacks[which]->command = strdup ("");
776 if (p->screenhacks[which]->enabled_p != enabled_p ||
777 !!strcasecmp (p->screenhacks[which]->visual, visual) ||
778 !!strcasecmp (p->screenhacks[which]->command, command))
780 /* Something was changed -- store results into the struct,
783 free (p->screenhacks[which]->visual);
784 free (p->screenhacks[which]->command);
785 p->screenhacks[which]->visual = strdup (visual);
786 p->screenhacks[which]->command = strdup (command);
787 p->screenhacks[which]->enabled_p = enabled_p;
789 return demo_write_init_file (widget, p);
792 /* No changes made */
796 void prefs_ok_cb (GtkButton *button, gpointer user_data);
799 apply_changes_and_save (GtkWidget *widget)
801 prefs_ok_cb ((GtkButton *) widget, 0);
802 return apply_changes_and_save_1 (widget);
807 run_this_cb (GtkButton *button, gpointer user_data)
809 int which = selected_hack_number (GTK_WIDGET (button));
810 if (which < 0) return;
811 if (0 == apply_changes_and_save (GTK_WIDGET (button)))
812 run_hack (GTK_WIDGET (button), which, True);
817 manual_cb (GtkButton *button, gpointer user_data)
819 /* prefs_pair *pair = (prefs_pair *) client_data; */
820 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
821 saver_preferences *p = pair->a;
822 GtkList *list_widget =
823 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
824 int which = selected_hack_number (GTK_WIDGET (button));
825 char *name, *name2, *cmd, *s;
826 if (which < 0) return;
827 apply_changes_and_save (GTK_WIDGET (button));
828 ensure_selected_item_visible (GTK_WIDGET (list_widget));
830 name = strdup (p->screenhacks[which]->command);
832 while (isspace (*name2)) name2++;
834 while (*s && !isspace (*s)) s++;
836 s = strrchr (name2, '/');
839 cmd = get_string_resource ("manualCommand", "ManualCommand");
842 char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
844 sprintf (cmd2 + strlen (cmd2),
846 name2, name2, name2, name2);
847 strcat (cmd2, " ) &");
853 warning_dialog (GTK_WIDGET (button),
854 "Error:\n\nno `manualCommand' resource set.",
863 run_next_cb (GtkButton *button, gpointer user_data)
865 /* prefs_pair *pair = (prefs_pair *) client_data; */
866 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
867 saver_preferences *p = pair->a;
869 GtkList *list_widget =
870 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
871 int which = selected_hack_number (GTK_WIDGET (button));
878 if (which >= p->screenhacks_count)
881 apply_changes_and_save (GTK_WIDGET (button));
882 gtk_list_select_item (GTK_LIST (list_widget), which);
883 ensure_selected_item_visible (GTK_WIDGET (list_widget));
884 populate_demo_window (GTK_WIDGET (button), which, pair);
885 run_hack (GTK_WIDGET (button), which, False);
890 run_prev_cb (GtkButton *button, gpointer user_data)
892 /* prefs_pair *pair = (prefs_pair *) client_data; */
893 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
894 saver_preferences *p = pair->a;
896 GtkList *list_widget =
897 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
898 int which = selected_hack_number (GTK_WIDGET (button));
901 which = p->screenhacks_count - 1;
906 which = p->screenhacks_count - 1;
908 apply_changes_and_save (GTK_WIDGET (button));
909 gtk_list_select_item (GTK_LIST (list_widget), which);
910 ensure_selected_item_visible (GTK_WIDGET (list_widget));
911 populate_demo_window (GTK_WIDGET (button), which, pair);
912 run_hack (GTK_WIDGET (button), which, False);
916 /* Helper for the text fields that contain time specifications:
917 this parses the text, and does error checking.
920 hack_time_text (GtkWidget *widget, const char *line, Time *store, Bool sec_p)
925 value = parse_time ((char *) line, sec_p, True);
926 value *= 1000; /* Time measures in microseconds */
932 "Unparsable time format: \"%s\"\n",
934 warning_dialog (widget, b, False, 100);
943 directory_p (const char *path)
948 else if (stat (path, &st))
950 else if (!S_ISDIR (st.st_mode))
957 normalize_directory (const char *path)
963 p2 = (char *) malloc (L + 2);
965 if (p2[L-1] == '/') /* remove trailing slash */
968 for (s = p2; s && *s; s++)
971 (!strncmp (s, "/../", 4) || /* delete "XYZ/../" */
972 !strncmp (s, "/..\000", 4))) /* delete "XYZ/..$" */
975 while (s0 > p2 && s0[-1] != '/')
985 else if (*s == '/' && !strncmp (s, "/./", 3)) /* delete "/./" */
986 strcpy (s, s+2), s--;
987 else if (*s == '/' && !strncmp (s, "/.\000", 3)) /* delete "/.$" */
991 for (s = p2; s && *s; s++) /* normalize consecutive slashes */
992 while (s[0] == '/' && s[1] == '/')
1000 prefs_ok_cb (GtkButton *button, gpointer user_data)
1002 /* prefs_pair *pair = (prefs_pair *) client_data; */
1003 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1005 saver_preferences *p = pair->a;
1006 saver_preferences *p2 = pair->b;
1007 Bool changed = False;
1009 # define SECONDS(field, name) \
1010 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
1011 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
1015 # define MINUTES(field, name) \
1016 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
1017 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
1021 # define INTEGER(field, name) do { \
1022 char *line = gtk_entry_get_text (\
1023 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
1024 unsigned int value; \
1028 else if (sscanf (line, "%u%c", &value, &c) != 1) \
1031 sprintf (b, "Error:\n\n" "Not an integer: \"%s\"\n", line); \
1032 warning_dialog (GTK_WIDGET (button), b, False, 100); \
1038 # define PATHNAME(field, name) do { \
1039 char *line = gtk_entry_get_text (\
1040 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
1043 else if (!directory_p (line)) \
1046 sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n", line); \
1047 warning_dialog (GTK_WIDGET (button), b, False, 100); \
1050 if ((field)) free ((field)); \
1051 (field) = strdup(line); \
1055 # define CHECKBOX(field, name) \
1056 field = gtk_toggle_button_get_active (\
1057 GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET(button), (name))))
1059 MINUTES (&p2->timeout, "timeout_text");
1060 MINUTES (&p2->cycle, "cycle_text");
1061 CHECKBOX (p2->lock_p, "lock_button");
1062 MINUTES (&p2->lock_timeout, "lock_text");
1064 CHECKBOX (p2->dpms_enabled_p, "dpms_button");
1065 MINUTES (&p2->dpms_standby, "dpms_standby_text");
1066 MINUTES (&p2->dpms_suspend, "dpms_suspend_text");
1067 MINUTES (&p2->dpms_off, "dpms_off_text");
1069 CHECKBOX (p2->grab_desktop_p, "grab_desk_button");
1070 CHECKBOX (p2->grab_video_p, "grab_video_button");
1071 CHECKBOX (p2->random_image_p, "grab_image_button");
1072 PATHNAME (p2->image_directory, "image_text");
1074 CHECKBOX (p2->verbose_p, "verbose_button");
1075 CHECKBOX (p2->capture_stderr_p, "capture_button");
1076 CHECKBOX (p2->splash_p, "splash_button");
1078 CHECKBOX (p2->install_cmap_p, "install_button");
1079 CHECKBOX (p2->fade_p, "fade_button");
1080 CHECKBOX (p2->unfade_p, "unfade_button");
1081 SECONDS (&p2->fade_seconds, "fade_text");
1089 # define COPY(field) \
1090 if (p->field != p2->field) changed = True; \
1091 p->field = p2->field
1098 COPY(dpms_enabled_p);
1103 COPY (grab_desktop_p);
1104 COPY (grab_video_p);
1105 COPY (random_image_p);
1107 if (!p->image_directory ||
1108 !p2->image_directory ||
1109 strcmp(p->image_directory, p2->image_directory))
1111 if (p->image_directory && p->image_directory != p2->image_directory)
1112 free (p->image_directory);
1113 p->image_directory = normalize_directory (p2->image_directory);
1114 if (p2->image_directory) free (p2->image_directory);
1115 p2->image_directory = 0;
1118 COPY(capture_stderr_p);
1121 COPY(install_cmap_p);
1127 populate_prefs_page (GTK_WIDGET (button), pair);
1131 Display *dpy = gdk_display;
1132 sync_server_dpms_settings (dpy, p->dpms_enabled_p,
1133 p->dpms_standby / 1000,
1134 p->dpms_suspend / 1000,
1138 demo_write_init_file (GTK_WIDGET (button), p);
1144 prefs_cancel_cb (GtkButton *button, gpointer user_data)
1146 /* prefs_pair *pair = (prefs_pair *) client_data; */
1147 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1149 *pair->b = *pair->a;
1150 populate_prefs_page (GTK_WIDGET (button), pair);
1155 pref_changed_cb (GtkButton *button, gpointer user_data)
1157 if (! initializing_p)
1158 apply_changes_and_save (GTK_WIDGET (button));
1163 list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
1164 gpointer client_data)
1166 if (event->type == GDK_2BUTTON_PRESS)
1168 GtkList *list = GTK_LIST (name_to_widget (button, "list"));
1169 int which = gtk_list_child_position (list, GTK_WIDGET (button));
1172 run_hack (GTK_WIDGET (button), which, True);
1180 list_select_cb (GtkList *list, GtkWidget *child)
1182 /* prefs_pair *pair = (prefs_pair *) client_data; */
1183 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1185 int which = gtk_list_child_position (list, GTK_WIDGET (child));
1186 apply_changes_and_save (GTK_WIDGET (list));
1187 populate_demo_window (GTK_WIDGET (list), which, pair);
1191 list_unselect_cb (GtkList *list, GtkWidget *child)
1193 /* prefs_pair *pair = (prefs_pair *) client_data; */
1194 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1196 apply_changes_and_save (GTK_WIDGET (list));
1197 populate_demo_window (GTK_WIDGET (list), -1, pair);
1201 static int updating_enabled_cb = 0; /* kludge to make sure that enabled_cb
1202 is only run by user action, not by
1205 /* Called when the checkboxes that are in the left column of the
1206 scrolling list are clicked. This both populates the right pane
1207 (just as clicking on the label (really, listitem) does) and
1208 also syncs this checkbox with the right pane Enabled checkbox.
1211 list_checkbox_cb (GtkWidget *cb, gpointer client_data)
1213 prefs_pair *pair = (prefs_pair *) client_data;
1215 GtkWidget *line_hbox = GTK_WIDGET (cb)->parent;
1216 GtkWidget *line = GTK_WIDGET (line_hbox)->parent;
1218 GtkList *list = GTK_LIST (GTK_WIDGET (line)->parent);
1219 GtkViewport *vp = GTK_VIEWPORT (GTK_WIDGET (list)->parent);
1220 GtkScrolledWindow *scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
1224 GtkToggleButton *enabled =
1225 GTK_TOGGLE_BUTTON (name_to_widget (cb, "enabled"));
1227 int which = gtk_list_child_position (list, line);
1229 /* remember previous scroll position of the top of the list */
1230 adj = gtk_scrolled_window_get_vadjustment (scroller);
1231 scroll_top = adj->value;
1233 apply_changes_and_save (GTK_WIDGET (list));
1234 gtk_list_select_item (list, which);
1235 /* ensure_selected_item_visible (GTK_WIDGET (list)); */
1236 populate_demo_window (GTK_WIDGET (list), which, pair);
1238 updating_enabled_cb++;
1239 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (enabled),
1240 GTK_TOGGLE_BUTTON (cb)->active);
1241 updating_enabled_cb--;
1243 /* restore the previous scroll position of the top of the list.
1244 this is weak, but I don't really know why it's moving... */
1245 gtk_adjustment_set_value (adj, scroll_top);
1249 /* Called when the right pane Enabled checkbox is clicked. This syncs
1250 the corresponding checkbox inside the scrolling list to the state
1254 enabled_cb (GtkWidget *cb, gpointer client_data)
1256 int which = selected_hack_number (cb);
1258 if (updating_enabled_cb) return;
1262 GtkList *list = GTK_LIST (name_to_widget (cb, "list"));
1263 GList *kids = GTK_LIST (list)->children;
1264 GtkWidget *line = GTK_WIDGET (g_list_nth_data (kids, which));
1265 GtkWidget *line_hbox = GTK_WIDGET (GTK_BIN (line)->child);
1266 GtkWidget *line_check =
1267 GTK_WIDGET (gtk_container_children (GTK_CONTAINER (line_hbox))->data);
1269 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (line_check),
1270 GTK_TOGGLE_BUTTON (cb)->active);
1278 GtkFileSelection *widget;
1279 } file_selection_data;
1284 store_image_directory (GtkWidget *button, gpointer user_data)
1286 file_selection_data *fsd = (file_selection_data *) user_data;
1287 prefs_pair *pair = fsd->pair;
1288 GtkFileSelection *selector = fsd->widget;
1289 GtkWidget *top = toplevel_widget;
1290 saver_preferences *p = pair->a;
1291 char *path = gtk_file_selection_get_filename (selector);
1293 if (p->image_directory && !strcmp(p->image_directory, path))
1294 return; /* no change */
1296 if (!directory_p (path))
1299 sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n", path);
1300 warning_dialog (GTK_WIDGET (top), b, False, 100);
1304 if (p->image_directory) free (p->image_directory);
1305 p->image_directory = normalize_directory (path);
1307 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "image_text")),
1308 (p->image_directory ? p->image_directory : ""));
1309 demo_write_init_file (GTK_WIDGET (top), p);
1314 browse_image_dir_cancel (GtkWidget *button, gpointer user_data)
1316 file_selection_data *fsd = (file_selection_data *) user_data;
1317 gtk_widget_hide (GTK_WIDGET (fsd->widget));
1321 browse_image_dir_ok (GtkWidget *button, gpointer user_data)
1323 browse_image_dir_cancel (button, user_data);
1324 store_image_directory (button, user_data);
1328 browse_image_dir_close (GtkWidget *widget, GdkEvent *event, gpointer user_data)
1330 browse_image_dir_cancel (widget, user_data);
1335 browse_image_dir_cb (GtkButton *button, gpointer user_data)
1337 /* prefs_pair *pair = (prefs_pair *) client_data; */
1338 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
1339 saver_preferences *p = pair->a;
1340 static file_selection_data *fsd = 0;
1342 GtkFileSelection *selector = GTK_FILE_SELECTION(
1343 gtk_file_selection_new ("Please select the image directory."));
1346 fsd = (file_selection_data *) malloc (sizeof (*fsd));
1348 fsd->widget = selector;
1351 if (p->image_directory && *p->image_directory)
1352 gtk_file_selection_set_filename (selector, p->image_directory);
1354 gtk_signal_connect (GTK_OBJECT (selector->ok_button),
1355 "clicked", GTK_SIGNAL_FUNC (browse_image_dir_ok),
1357 gtk_signal_connect (GTK_OBJECT (selector->cancel_button),
1358 "clicked", GTK_SIGNAL_FUNC (browse_image_dir_cancel),
1360 gtk_signal_connect (GTK_OBJECT (selector), "delete_event",
1361 GTK_SIGNAL_FUNC (browse_image_dir_close),
1364 gtk_widget_set_sensitive (GTK_WIDGET (selector->file_list), False);
1366 gtk_window_set_modal (GTK_WINDOW (selector), True);
1367 gtk_widget_show (GTK_WIDGET (selector));
1372 /* Populating the various widgets
1376 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
1379 format_time (char *buf, Time time)
1381 int s = time / 1000;
1382 unsigned int h = 0, m = 0;
1393 sprintf (buf, "%u:%02u:%02u", h, m, s);
1397 /* Finds the number of the last hack to run, and makes that item be
1398 selected by default.
1401 scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
1403 saver_preferences *p = pair->a;
1406 unsigned long nitems, bytesafter;
1408 Display *dpy = gdk_display;
1412 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
1413 XA_SCREENSAVER_STATUS,
1414 0, 3, False, XA_INTEGER,
1415 &type, &format, &nitems, &bytesafter,
1416 (unsigned char **) &data)
1418 && type == XA_INTEGER
1421 which = (int) data[2] - 1;
1423 if (data) free (data);
1428 list = GTK_LIST (name_to_widget (toplevel, "list"));
1429 apply_changes_and_save (toplevel);
1430 if (which < p->screenhacks_count)
1432 gtk_list_select_item (list, which);
1433 ensure_selected_item_visible (GTK_WIDGET (list));
1434 populate_demo_window (toplevel, which, pair);
1441 populate_hack_list (GtkWidget *toplevel, prefs_pair *pair)
1443 saver_preferences *p = pair->a;
1444 GtkList *list = GTK_LIST (name_to_widget (toplevel, "list"));
1445 screenhack **hacks = p->screenhacks;
1448 for (h = hacks; h && *h; h++)
1450 /* A GtkList must contain only GtkListItems, but those can contain
1451 an arbitrary widget. We add an Hbox, and inside that, a Checkbox
1452 and a Label. We handle single and double click events on the
1453 line itself, for clicking on the text, but the interior checkbox
1454 also handles its own events.
1457 GtkWidget *line_hbox;
1458 GtkWidget *line_check;
1459 GtkWidget *line_label;
1461 char *pretty_name = (h[0]->name
1462 ? strdup (h[0]->name)
1463 : make_hack_name (h[0]->command));
1465 line = gtk_list_item_new ();
1466 line_hbox = gtk_hbox_new (FALSE, 0);
1467 line_check = gtk_check_button_new ();
1468 line_label = gtk_label_new (pretty_name);
1470 gtk_container_add (GTK_CONTAINER (line), line_hbox);
1471 gtk_box_pack_start (GTK_BOX (line_hbox), line_check, FALSE, FALSE, 0);
1472 gtk_box_pack_start (GTK_BOX (line_hbox), line_label, FALSE, FALSE, 0);
1474 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (line_check),
1476 gtk_label_set_justify (GTK_LABEL (line_label), GTK_JUSTIFY_LEFT);
1478 gtk_widget_show (line_check);
1479 gtk_widget_show (line_label);
1480 gtk_widget_show (line_hbox);
1481 gtk_widget_show (line);
1485 gtk_container_add (GTK_CONTAINER (list), line);
1486 gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
1487 GTK_SIGNAL_FUNC (list_doubleclick_cb),
1490 gtk_signal_connect (GTK_OBJECT (line_check), "toggled",
1491 GTK_SIGNAL_FUNC (list_checkbox_cb),
1495 GTK_WIDGET (GTK_BIN(line)->child)->style =
1496 gtk_style_copy (GTK_WIDGET (text_line)->style);
1498 gtk_widget_show (line);
1501 gtk_signal_connect (GTK_OBJECT (list), "select_child",
1502 GTK_SIGNAL_FUNC (list_select_cb),
1504 gtk_signal_connect (GTK_OBJECT (list), "unselect_child",
1505 GTK_SIGNAL_FUNC (list_unselect_cb),
1511 populate_prefs_page (GtkWidget *top, prefs_pair *pair)
1513 saver_preferences *p = pair->a;
1516 format_time (s, p->timeout);
1517 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "timeout_text")), s);
1518 format_time (s, p->cycle);
1519 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "cycle_text")), s);
1520 format_time (s, p->lock_timeout);
1521 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "lock_text")), s);
1523 format_time (s, p->dpms_standby);
1524 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "dpms_standby_text")),s);
1525 format_time (s, p->dpms_suspend);
1526 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "dpms_suspend_text")),s);
1527 format_time (s, p->dpms_off);
1528 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "dpms_off_text")), s);
1530 format_time (s, p->fade_seconds);
1531 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "fade_text")), s);
1533 gtk_toggle_button_set_active (
1534 GTK_TOGGLE_BUTTON (name_to_widget (top, "lock_button")),
1536 gtk_toggle_button_set_active (
1537 GTK_TOGGLE_BUTTON (name_to_widget (top, "verbose_button")),
1539 gtk_toggle_button_set_active (
1540 GTK_TOGGLE_BUTTON (name_to_widget (top, "capture_button")),
1541 p->capture_stderr_p);
1542 gtk_toggle_button_set_active (
1543 GTK_TOGGLE_BUTTON (name_to_widget (top, "splash_button")),
1546 gtk_toggle_button_set_active (
1547 GTK_TOGGLE_BUTTON (name_to_widget (top, "dpms_button")),
1550 gtk_toggle_button_set_active (
1551 GTK_TOGGLE_BUTTON (name_to_widget (top,"grab_desk_button")),
1553 gtk_toggle_button_set_active (
1554 GTK_TOGGLE_BUTTON (name_to_widget(top,"grab_video_button")),
1556 gtk_toggle_button_set_active (
1557 GTK_TOGGLE_BUTTON (name_to_widget(top,"grab_image_button")),
1559 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "image_text")),
1560 (p->image_directory ? p->image_directory : ""));
1561 gtk_widget_set_sensitive (GTK_WIDGET (name_to_widget (top, "image_text")),
1563 gtk_widget_set_sensitive (
1564 GTK_WIDGET (name_to_widget (top,"image_browse_button")),
1567 gtk_toggle_button_set_active (
1568 GTK_TOGGLE_BUTTON (name_to_widget (top, "install_button")),
1570 gtk_toggle_button_set_active (
1571 GTK_TOGGLE_BUTTON (name_to_widget (top, "fade_button")),
1573 gtk_toggle_button_set_active (
1574 GTK_TOGGLE_BUTTON (name_to_widget (top, "unfade_button")),
1579 Bool found_any_writable_cells = False;
1580 Bool dpms_supported = False;
1582 Display *dpy = gdk_display;
1583 int nscreens = ScreenCount(dpy);
1585 for (i = 0; i < nscreens; i++)
1587 Screen *s = ScreenOfDisplay (dpy, i);
1588 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1590 found_any_writable_cells = True;
1595 #ifdef HAVE_XF86VMODE_GAMMA
1596 found_any_writable_cells = True; /* if we can gamma fade, go for it */
1599 #ifdef HAVE_DPMS_EXTENSION
1601 int op = 0, event = 0, error = 0;
1602 if (XQueryExtension (dpy, "DPMS", &op, &event, &error))
1603 dpms_supported = True;
1605 #endif /* HAVE_DPMS_EXTENSION */
1608 /* Blanking and Locking
1610 gtk_widget_set_sensitive (
1611 GTK_WIDGET (name_to_widget (top, "lock_label")),
1613 gtk_widget_set_sensitive (
1614 GTK_WIDGET (name_to_widget (top, "lock_text")),
1619 gtk_widget_set_sensitive (
1620 GTK_WIDGET (name_to_widget (top, "dpms_frame")),
1622 gtk_widget_set_sensitive (
1623 GTK_WIDGET (name_to_widget (top, "dpms_button")),
1625 gtk_widget_set_sensitive (
1626 GTK_WIDGET (name_to_widget (top, "dpms_standby_label")),
1627 dpms_supported && p->dpms_enabled_p);
1628 gtk_widget_set_sensitive (
1629 GTK_WIDGET (name_to_widget (top, "dpms_standby_text")),
1630 dpms_supported && p->dpms_enabled_p);
1631 gtk_widget_set_sensitive (
1632 GTK_WIDGET (name_to_widget (top, "dpms_suspend_label")),
1633 dpms_supported && p->dpms_enabled_p);
1634 gtk_widget_set_sensitive (
1635 GTK_WIDGET (name_to_widget (top, "dpms_suspend_text")),
1636 dpms_supported && p->dpms_enabled_p);
1637 gtk_widget_set_sensitive (
1638 GTK_WIDGET (name_to_widget (top, "dpms_off_label")),
1639 dpms_supported && p->dpms_enabled_p);
1640 gtk_widget_set_sensitive (
1641 GTK_WIDGET (name_to_widget (top, "dpms_off_text")),
1642 dpms_supported && p->dpms_enabled_p);
1646 gtk_widget_set_sensitive (
1647 GTK_WIDGET (name_to_widget (top, "cmap_frame")),
1648 found_any_writable_cells);
1649 gtk_widget_set_sensitive (
1650 GTK_WIDGET (name_to_widget (top, "install_button")),
1651 found_any_writable_cells);
1652 gtk_widget_set_sensitive (
1653 GTK_WIDGET (name_to_widget (top, "fade_button")),
1654 found_any_writable_cells);
1655 gtk_widget_set_sensitive (
1656 GTK_WIDGET (name_to_widget (top, "unfade_button")),
1657 found_any_writable_cells);
1659 gtk_widget_set_sensitive (
1660 GTK_WIDGET (name_to_widget (top, "fade_label")),
1661 (found_any_writable_cells &&
1662 (p->fade_p || p->unfade_p)));
1663 gtk_widget_set_sensitive (
1664 GTK_WIDGET (name_to_widget (top, "fade_text")),
1665 (found_any_writable_cells &&
1666 (p->fade_p || p->unfade_p)));
1673 sensitize_demo_widgets (GtkWidget *toplevel, Bool sensitive_p)
1675 const char *names[] = { "cmd_label", "cmd_text", "enabled",
1676 "visual", "visual_combo",
1679 for (i = 0; i < countof(names); i++)
1681 GtkWidget *w = name_to_widget (toplevel, names[i]);
1682 gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
1685 /* I don't know how to handle these yet... */
1687 const char *names2[] = { "cut_menu", "copy_menu", "paste_menu" };
1688 for (i = 0; i < countof(names2); i++)
1690 GtkWidget *w = name_to_widget (toplevel, names2[i]);
1691 gtk_widget_set_sensitive (GTK_WIDGET(w), False);
1697 /* Even though we've given these text fields a maximum number of characters,
1698 their default size is still about 30 characters wide -- so measure out
1699 a string in their font, and resize them to just fit that.
1702 fix_text_entry_sizes (GtkWidget *toplevel)
1704 const char *names[] = { "timeout_text", "cycle_text", "lock_text",
1705 "dpms_standby_text", "dpms_suspend_text",
1706 "dpms_off_text", "fade_text" };
1711 for (i = 0; i < countof(names); i++)
1713 w = GTK_WIDGET (name_to_widget (toplevel, names[i]));
1715 width = gdk_text_width (w->style->font, "00:00:00_", 9);
1716 gtk_widget_set_usize (w, width, -2);
1719 /* Now fix the size of the combo box.
1721 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "visual_combo"));
1722 w = GTK_COMBO (w)->entry;
1723 width = gdk_text_width (w->style->font, "PseudoColor___", 14);
1724 gtk_widget_set_usize (w, width, -2);
1726 /* Now fix the size of the file entry text.
1728 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "image_text"));
1729 width = gdk_text_width (w->style->font, "MMMMMMMMMMMMMM", 14);
1730 gtk_widget_set_usize (w, width, -2);
1733 /* Now fix the size of the list.
1735 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "list"));
1736 width = gdk_text_width (w->style->font, "nnnnnnnnnnnnnnnnnnnnnn", 22);
1737 gtk_widget_set_usize (w, width, -2);
1744 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...)
1747 static char *up_arrow_xpm[] = {
1770 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1771 the end of the array (Gtk 1.2.5.) */
1772 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1773 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1776 static char *down_arrow_xpm[] = {
1799 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1800 the end of the array (Gtk 1.2.5.) */
1801 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1802 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1806 pixmapify_button (GtkWidget *toplevel, int down_p)
1810 GtkWidget *pixmapwid;
1814 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel),
1815 (down_p ? "next" : "prev")));
1816 style = gtk_widget_get_style (w);
1818 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1819 &style->bg[GTK_STATE_NORMAL],
1821 ? (gchar **) down_arrow_xpm
1822 : (gchar **) up_arrow_xpm));
1823 pixmapwid = gtk_pixmap_new (pixmap, mask);
1824 gtk_widget_show (pixmapwid);
1825 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1826 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1830 map_next_button_cb (GtkWidget *w, gpointer user_data)
1832 pixmapify_button (w, 1);
1836 map_prev_button_cb (GtkWidget *w, gpointer user_data)
1838 pixmapify_button (w, 0);
1843 /* Work around a Gtk bug that causes label widgets to wrap text too early.
1847 you_are_not_a_unique_or_beautiful_snowflake (GtkWidget *label,
1848 GtkAllocation *allocation,
1852 GtkWidgetAuxInfo *aux_info;
1854 aux_info = gtk_object_get_data (GTK_OBJECT (label), "gtk-aux-info");
1856 aux_info->width = allocation->width;
1857 aux_info->height = -2;
1861 gtk_widget_size_request (label, &req);
1865 /* Feel the love. Thanks to Nat Friedman for finding this workaround.
1868 eschew_gtk_lossage (GtkWidget *toplevel)
1870 GtkWidgetAuxInfo *aux_info;
1871 GtkWidget *label = GTK_WIDGET (name_to_widget (toplevel, "doc"));
1873 aux_info = g_new0 (GtkWidgetAuxInfo, 1);
1874 aux_info->width = label->allocation.width;
1875 aux_info->height = -2;
1879 gtk_object_set_data (GTK_OBJECT (label), "gtk-aux-info", aux_info);
1881 gtk_signal_connect (GTK_OBJECT (label), "size_allocate",
1882 you_are_not_a_unique_or_beautiful_snowflake, NULL);
1884 gtk_widget_queue_resize (label);
1889 get_hack_blurb (screenhack *hack)
1892 char *prog_name = strdup (hack->command);
1893 char *pretty_name = (hack->name
1894 ? strdup (hack->name)
1895 : make_hack_name (hack->command));
1896 char doc_name[255], doc_class[255];
1899 for (s = prog_name; *s && !isspace(*s); s++)
1902 s = strrchr (prog_name, '/');
1903 if (s) strcpy (prog_name, s+1);
1905 sprintf (doc_name, "hacks.%s.documentation", pretty_name);
1906 sprintf (doc_class, "hacks.%s.documentation", prog_name);
1910 doc_string = get_string_resource (doc_name, doc_class);
1913 for (s = doc_string; *s; s++)
1917 /* skip over whitespace at beginning of line */
1919 while (*s && (*s == ' ' || *s == '\t'))
1922 else if (*s == ' ' || *s == '\t')
1924 /* compress all other horizontal whitespace. */
1927 for (s2 = s; *s2 && (*s2 == ' ' || *s2 == '\t'); s2++)
1929 if (s2 > s) strcpy (s, s2);
1934 while (*s && isspace (*s)) /* Strip trailing whitespace */
1937 /* Delete whitespace at end of each line. */
1938 for (; s > doc_string; s--)
1939 if (*s == '\n' && (s[-1] == ' ' || s[-1] == '\t'))
1942 s2 > doc_string && (*s2 == ' ' || *s2 == '\t');
1946 if (s2 < s) strcpy (s2, s);
1950 /* Delete leading blank lines. */
1951 for (s = doc_string; *s == '\n'; s++)
1953 if (s > doc_string) strcpy (doc_string, s);
1957 static int doc_installed = 0;
1958 if (doc_installed == 0)
1960 if (get_boolean_resource ("hacks.documentation.isInstalled",
1961 "hacks.documentation.isInstalled"))
1967 if (doc_installed < 0)
1969 strdup ("Error:\n\n"
1970 "The documentation strings do not appear to be "
1971 "installed. This is probably because there is "
1972 "an \"XScreenSaver\" app-defaults file installed "
1973 "that is from an older version of the program. "
1974 "To fix this problem, delete that file, or "
1975 "install a current version (either will work.)");
1977 doc_string = strdup ("");
1985 populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
1987 saver_preferences *p = pair->a;
1988 screenhack *hack = (which >= 0 && which < p->screenhacks_count
1989 ? p->screenhacks[which] : 0);
1990 GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
1991 GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
1992 GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
1993 GtkToggleButton *enabled =
1994 GTK_TOGGLE_BUTTON (name_to_widget (toplevel, "enabled"));
1995 GtkCombo *vis = GTK_COMBO (name_to_widget (toplevel, "visual_combo"));
1997 char *pretty_name = (hack
1999 ? strdup (hack->name)
2000 : make_hack_name (hack->command))
2002 char *doc_string = hack ? get_hack_blurb (hack) : 0;
2004 gtk_frame_set_label (frame, (pretty_name ? pretty_name : ""));
2005 gtk_label_set_text (doc, (doc_string ? doc_string : ""));
2006 gtk_entry_set_text (cmd, (hack ? hack->command : ""));
2007 gtk_entry_set_position (cmd, 0);
2009 updating_enabled_cb++;
2010 gtk_toggle_button_set_active (enabled, (hack ? hack->enabled_p : False));
2011 updating_enabled_cb--;
2013 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry),
2015 ? (hack->visual && *hack->visual
2020 gtk_container_resize_children (GTK_CONTAINER (GTK_WIDGET (doc)->parent));
2022 sensitize_demo_widgets (toplevel, (hack ? True : False));
2024 if (pretty_name) free (pretty_name);
2025 if (doc_string) free (doc_string);
2027 _selected_hack_number = which;
2032 widget_deleter (GtkWidget *widget, gpointer data)
2034 /* #### Well, I want to destroy these widgets, but if I do that, they get
2035 referenced again, and eventually I get a SEGV. So instead of
2036 destroying them, I'll just hide them, and leak a bunch of memory
2037 every time the disk file changes. Go go go Gtk!
2039 #### Ok, that's a lie, I get a crash even if I just hide the widget
2040 and don't ever delete it. Fuck!
2043 gtk_widget_destroy (widget);
2045 gtk_widget_hide (widget);
2051 maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair)
2054 saver_preferences *p = pair->a;
2056 static Bool reentrant_lock = False;
2057 if (reentrant_lock) return 0;
2058 reentrant_lock = True;
2060 if (init_file_changed_p (p))
2062 const char *f = init_file_name();
2067 if (!f || !*f) return 0;
2068 b = (char *) malloc (strlen(f) + 1024);
2071 "file \"%s\" has changed, reloading.\n",
2073 warning_dialog (widget, b, False, 100);
2078 which = selected_hack_number (widget);
2079 list = GTK_LIST (name_to_widget (widget, "list"));
2080 gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL);
2081 populate_hack_list (widget, pair);
2082 gtk_list_select_item (list, which);
2083 populate_prefs_page (widget, pair);
2084 populate_demo_window (widget, which, pair);
2085 ensure_selected_item_visible (GTK_WIDGET (list));
2090 reentrant_lock = False;
2096 /* Setting window manager icon
2100 init_icon (GdkWindow *window)
2102 GdkBitmap *mask = 0;
2105 gdk_pixmap_create_from_xpm_d (window, &mask, &transp,
2106 (gchar **) logo_50_xpm);
2108 gdk_window_set_icon (window, 0, pixmap, mask);
2112 /* The main demo-mode command loop.
2117 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
2118 XrmRepresentation *type, XrmValue *value, XPointer closure)
2121 for (i = 0; quarks[i]; i++)
2123 if (bindings[i] == XrmBindTightly)
2124 fprintf (stderr, (i == 0 ? "" : "."));
2125 else if (bindings[i] == XrmBindLoosely)
2126 fprintf (stderr, "*");
2128 fprintf (stderr, " ??? ");
2129 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
2132 fprintf (stderr, ": %s\n", (char *) value->addr);
2140 the_network_is_not_the_computer (GtkWidget *parent)
2142 Display *dpy = gdk_display;
2143 char *rversion, *ruser, *rhost;
2144 char *luser, *lhost;
2146 struct passwd *p = getpwuid (getuid ());
2147 const char *d = DisplayString (dpy);
2149 # if defined(HAVE_UNAME)
2151 if (uname (&uts) < 0)
2152 lhost = "<UNKNOWN>";
2154 lhost = uts.nodename;
2156 strcpy (lhost, getenv("SYS$NODE"));
2157 # else /* !HAVE_UNAME && !VMS */
2158 strcat (lhost, "<UNKNOWN>");
2159 # endif /* !HAVE_UNAME && !VMS */
2161 if (p && p->pw_name)
2166 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
2168 /* Make a buffer that's big enough for a number of copies of all the
2169 strings, plus some. */
2170 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
2171 (ruser ? strlen(ruser) : 0) +
2172 (rhost ? strlen(rhost) : 0) +
2179 if (!rversion || !*rversion)
2183 "The XScreenSaver daemon doesn't seem to be running\n"
2184 "on display \"%s\". Launch it now?",
2187 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
2189 /* Warn that the two processes are running as different users.
2193 "%s is running as user \"%s\" on host \"%s\".\n"
2194 "But the xscreensaver managing display \"%s\"\n"
2195 "is running as user \"%s\" on host \"%s\".\n"
2197 "Since they are different users, they won't be reading/writing\n"
2198 "the same ~/.xscreensaver file, so %s isn't\n"
2199 "going to work right.\n"
2201 "You should either re-run %s as \"%s\", or re-run\n"
2202 "xscreensaver as \"%s\".\n"
2204 "Restart the xscreensaver daemon now?\n",
2205 progname, luser, lhost,
2207 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
2209 progname, (ruser ? ruser : "???"),
2212 else if (rhost && *rhost && !!strcmp (rhost, lhost))
2214 /* Warn that the two processes are running on different hosts.
2218 "%s is running as user \"%s\" on host \"%s\".\n"
2219 "But the xscreensaver managing display \"%s\"\n"
2220 "is running as user \"%s\" on host \"%s\".\n"
2222 "If those two machines don't share a file system (that is,\n"
2223 "if they don't see the same ~%s/.xscreensaver file) then\n"
2224 "%s won't work right.\n"
2226 "Restart the daemon on \"%s\" as \"%s\" now?\n",
2227 progname, luser, lhost,
2229 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
2234 else if (!!strcmp (rversion, short_version))
2236 /* Warn that the version numbers don't match.
2240 "This is %s version %s.\n"
2241 "But the xscreensaver managing display \"%s\"\n"
2242 "is version %s. This could cause problems.\n"
2244 "Restart the xscreensaver daemon now?\n",
2245 progname, short_version,
2252 warning_dialog (parent, msg, True, 1);
2258 /* We use this error handler so that X errors are preceeded by the name
2259 of the program that generated them.
2262 demo_ehandler (Display *dpy, XErrorEvent *error)
2264 fprintf (stderr, "\nX error in %s:\n", progname);
2265 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
2268 fprintf (stderr, " (nonfatal.)\n");
2273 /* We use this error handler so that Gtk/Gdk errors are preceeded by the name
2274 of the program that generated them; and also that we can ignore one
2275 particular bogus error message that Gdk madly spews.
2278 g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
2279 const gchar *message, gpointer user_data)
2281 /* Ignore the message "Got event for unknown window: 0x...".
2282 Apparently some events are coming in for the xscreensaver window
2283 (presumably reply events related to the ClientMessage) and Gdk
2284 feels the need to complain about them. So, just suppress any
2285 messages that look like that one.
2287 if (strstr (message, "unknown window"))
2290 fprintf (stderr, "%s: %s-%s: %s%s", blurb(), log_domain,
2291 (log_level == G_LOG_LEVEL_ERROR ? "error" :
2292 log_level == G_LOG_LEVEL_CRITICAL ? "critical" :
2293 log_level == G_LOG_LEVEL_WARNING ? "warning" :
2294 log_level == G_LOG_LEVEL_MESSAGE ? "message" :
2295 log_level == G_LOG_LEVEL_INFO ? "info" :
2296 log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"),
2298 ((!*message || message[strlen(message)-1] != '\n')
2303 static char *defaults[] = {
2304 #include "XScreenSaver_ad.h"
2309 #ifdef HAVE_CRAPPLET
2310 static struct poptOption crapplet_options[] = {
2311 {NULL, '\0', 0, NULL, 0}
2313 #endif /* HAVE_CRAPPLET */
2317 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n", \
2322 map_window_cb (GtkWidget *w, gpointer user_data)
2324 Boolean oi = initializing_p;
2325 initializing_p = True;
2326 eschew_gtk_lossage (w);
2327 ensure_selected_item_visible (GTK_WIDGET(name_to_widget(w, "list")));
2328 initializing_p = oi;
2333 main (int argc, char **argv)
2336 prefs_pair Pair, *pair;
2337 saver_preferences P, P2, *p, *p2;
2341 Widget toplevel_shell;
2342 GtkWidget *gtk_window;
2343 char *real_progname = argv[0];
2346 initializing_p = True;
2348 s = strrchr (real_progname, '/');
2349 if (s) real_progname = s+1;
2356 memset (p, 0, sizeof (*p));
2357 memset (p2, 0, sizeof (*p2));
2359 global_prefs_pair = pair; /* I hate C so much... */
2361 progname = real_progname;
2363 short_version = (char *) malloc (5);
2364 memcpy (short_version, screensaver_id + 17, 4);
2365 short_version [4] = 0;
2368 /* Register our error message logger for every ``log domain'' known.
2369 There's no way to do this globally, so I grepped the Gtk/Gdk sources
2370 for all of the domains that seem to be in use.
2373 const char * const domains[] = { "Gtk", "Gdk", "GLib", "GModule",
2374 "GThread", "Gnome", "GnomeUI", 0 };
2375 for (i = 0; domains[i]; i++)
2376 g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0);
2379 /* This is gross, but Gtk understands --display and not -display...
2381 for (i = 1; i < argc; i++)
2382 if (argv[i][0] && argv[i][1] &&
2383 !strncmp(argv[i], "-display", strlen(argv[i])))
2384 argv[i] = "--display";
2387 /* We need to parse this arg really early... Sigh. */
2388 for (i = 1; i < argc; i++)
2390 (!strcmp(argv[i], "--crapplet") ||
2391 !strcmp(argv[i], "--capplet")))
2393 # ifdef HAVE_CRAPPLET
2396 for (j = i; j < argc; j++) /* remove it from the list */
2397 argv[j] = argv[j+1];
2400 # else /* !HAVE_CRAPPLET */
2401 fprintf (stderr, "%s: not compiled with --crapplet support\n",
2405 # endif /* !HAVE_CRAPPLET */
2408 /* Let Gtk open the X connection, then initialize Xt to use that
2409 same connection. Doctor Frankenstein would be proud.
2411 # ifdef HAVE_CRAPPLET
2414 GnomeClient *client;
2415 GnomeClientFlags flags = 0;
2417 int init_results = gnome_capplet_init ("screensaver-properties",
2419 argc, argv, NULL, 0, NULL);
2421 0 upon successful initialization;
2422 1 if --init-session-settings was passed on the cmdline;
2423 2 if --ignore was passed on the cmdline;
2426 So the 1 signifies just to init the settings, and quit, basically.
2427 (Meaning launch the xscreensaver daemon.)
2430 if (init_results < 0)
2433 g_error ("An initialization error occurred while "
2434 "starting xscreensaver-capplet.\n");
2436 fprintf (stderr, "%s: gnome_capplet_init failed: %d\n",
2437 real_progname, init_results);
2442 client = gnome_master_client ();
2445 flags = gnome_client_get_flags (client);
2447 if (flags & GNOME_CLIENT_IS_CONNECTED)
2450 gnome_startup_acquire_token ("GNOME_SCREENSAVER_PROPERTIES",
2451 gnome_client_get_id (client));
2454 char *session_args[20];
2456 session_args[i++] = real_progname;
2457 session_args[i++] = "--capplet";
2458 session_args[i++] = "--init-session-settings";
2459 session_args[i] = 0;
2460 gnome_client_set_priority (client, 20);
2461 gnome_client_set_restart_style (client, GNOME_RESTART_ANYWAY);
2462 gnome_client_set_restart_command (client, i, session_args);
2466 gnome_client_set_restart_style (client, GNOME_RESTART_NEVER);
2469 gnome_client_flush (client);
2472 if (init_results == 1)
2474 system ("xscreensaver -nosplash &");
2480 # endif /* HAVE_CRAPPLET */
2482 gtk_init (&argc, &argv);
2486 /* We must read exactly the same resources as xscreensaver.
2487 That means we must have both the same progclass *and* progname,
2488 at least as far as the resource database is concerned. So,
2489 put "xscreensaver" in argv[0] while initializing Xt.
2491 argv[0] = "xscreensaver";
2495 /* Teach Xt to use the Display that Gtk/Gdk have already opened.
2497 XtToolkitInitialize ();
2498 app = XtCreateApplicationContext ();
2500 XtAppSetFallbackResources (app, defaults);
2501 XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv);
2502 toplevel_shell = XtAppCreateShell (progname, progclass,
2503 applicationShellWidgetClass,
2506 dpy = XtDisplay (toplevel_shell);
2507 db = XtDatabase (dpy);
2508 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
2509 XSetErrorHandler (demo_ehandler);
2512 /* After doing Xt-style command-line processing, complain about any
2513 unrecognized command-line arguments.
2515 for (i = 1; i < argc; i++)
2518 if (s[0] == '-' && s[1] == '-')
2520 if (!strcmp (s, "-prefs"))
2522 else if (crapplet_p)
2523 /* There are lots of random args that we don't care about when we're
2524 started as a crapplet, so just ignore unknown args in that case. */
2528 fprintf (stderr, "%s: unknown option: %s\n", real_progname, argv[i]);
2534 /* Load the init file, which may end up consulting the X resource database
2535 and the site-wide app-defaults file. Note that at this point, it's
2536 important that `progname' be "xscreensaver", rather than whatever
2543 /* Now that Xt has been initialized, and the resources have been read,
2544 we can set our `progname' variable to something more in line with
2547 progname = real_progname;
2551 /* Print out all the resources we read. */
2553 XrmName name = { 0 };
2554 XrmClass class = { 0 };
2556 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
2562 /* Intern the atoms that xscreensaver_command() needs.
2564 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
2565 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
2566 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
2567 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
2568 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
2569 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
2570 XA_SELECT = XInternAtom (dpy, "SELECT", False);
2571 XA_DEMO = XInternAtom (dpy, "DEMO", False);
2572 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
2573 XA_BLANK = XInternAtom (dpy, "BLANK", False);
2574 XA_LOCK = XInternAtom (dpy, "LOCK", False);
2575 XA_EXIT = XInternAtom (dpy, "EXIT", False);
2576 XA_RESTART = XInternAtom (dpy, "RESTART", False);
2579 /* Create the window and all its widgets.
2581 gtk_window = create_xscreensaver_demo ();
2582 toplevel_widget = gtk_window;
2584 /* Set the window's title. */
2587 char *v = (char *) strdup(strchr(screensaver_id, ' '));
2588 char *s1, *s2, *s3, *s4;
2589 s1 = (char *) strchr(v, ' '); s1++;
2590 s2 = (char *) strchr(s1, ' ');
2591 s3 = (char *) strchr(v, '('); s3++;
2592 s4 = (char *) strchr(s3, ')');
2595 sprintf (title, "%.50s %.50s, %.50s", progclass, s1, s3);
2596 gtk_window_set_title (GTK_WINDOW (gtk_window), title);
2600 /* Various other widget initializations...
2602 gtk_signal_connect (GTK_OBJECT (gtk_window), "delete_event",
2603 GTK_SIGNAL_FUNC (wm_close_cb), NULL);
2605 populate_hack_list (gtk_window, pair);
2606 populate_prefs_page (gtk_window, pair);
2607 sensitize_demo_widgets (gtk_window, False);
2608 fix_text_entry_sizes (gtk_window);
2609 scroll_to_current_hack (gtk_window, pair);
2611 gtk_signal_connect (
2612 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "list")),
2613 "map", GTK_SIGNAL_FUNC(map_window_cb), 0);
2614 gtk_signal_connect (
2615 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "prev")),
2616 "map", GTK_SIGNAL_FUNC(map_prev_button_cb), 0);
2617 gtk_signal_connect (
2618 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "next")),
2619 "map", GTK_SIGNAL_FUNC(map_next_button_cb), 0);
2622 /* Handle the -prefs command-line argument. */
2625 GtkNotebook *notebook =
2626 GTK_NOTEBOOK (name_to_widget (gtk_window, "notebook"));
2627 gtk_notebook_set_page (notebook, 1);
2630 # ifdef HAVE_CRAPPLET
2634 GtkWidget *top_vbox;
2636 capplet = capplet_widget_new ();
2638 top_vbox = GTK_BIN (gtk_window)->child;
2640 gtk_widget_ref (top_vbox);
2641 gtk_container_remove (GTK_CONTAINER (gtk_window), top_vbox);
2642 GTK_OBJECT_SET_FLAGS (top_vbox, GTK_FLOATING);
2644 /* In crapplet-mode, take off the menubar. */
2645 gtk_widget_hide (name_to_widget (gtk_window, "menubar"));
2647 gtk_container_add (GTK_CONTAINER (capplet), top_vbox);
2648 gtk_widget_show (capplet);
2649 gtk_widget_hide (gtk_window);
2651 /* Hook up the Control Center's redundant Help button, too. */
2652 gtk_signal_connect (GTK_OBJECT (capplet), "help",
2653 GTK_SIGNAL_FUNC (doc_menu_cb), 0);
2655 /* Issue any warnings about the running xscreensaver daemon. */
2656 the_network_is_not_the_computer (top_vbox);
2659 # endif /* HAVE_CRAPPLET */
2661 gtk_widget_show (gtk_window);
2662 init_icon (GTK_WIDGET(gtk_window)->window);
2664 /* Issue any warnings about the running xscreensaver daemon. */
2665 the_network_is_not_the_computer (gtk_window);
2668 /* Run the Gtk event loop, and not the Xt event loop. This means that
2669 if there were Xt timers or fds registered, they would never get serviced,
2670 and if there were any Xt widgets, they would never have events delivered.
2671 Fortunately, we're using Gtk for all of the UI, and only initialized
2672 Xt so that we could process the command line and use the X resource
2675 initializing_p = False;
2677 # ifdef HAVE_CRAPPLET
2679 capplet_gtk_main ();
2681 # endif /* HAVE_CRAPPLET */
2687 #endif /* HAVE_GTK -- whole file */