+ /* Flush any checkbox changes in the list down into the prefs struct.
+ */
+#ifdef HAVE_GTK2
+ closure.s = s;
+ closure.changed = &changed;
+ closure.i = 0;
+ gtk_tree_model_foreach (model, flush_checkbox, &closure);
+
+#else /* !HAVE_GTK2 */
+
+ for (i = 0; kids; kids = kids->next, i++)
+ {
+ GtkWidget *line = GTK_WIDGET (kids->data);
+ GtkWidget *line_hbox = GTK_WIDGET (GTK_BIN (line)->child);
+ GtkWidget *line_check =
+ GTK_WIDGET (gtk_container_children (GTK_CONTAINER (line_hbox))->data);
+ Bool checked =
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (line_check));
+
+ if (flush_changes (s, i, (checked ? 1 : 0), 0, 0))
+ changed = True;
+ }
+#endif /* ~HAVE_GTK2 */
+
+ /* Flush the non-hack-specific settings down into the prefs struct.
+ */
+
+# define SECONDS(FIELD,NAME) \
+ w = name_to_widget (s, (NAME)); \
+ hack_time_text (s, gtk_entry_get_text (GTK_ENTRY (w)), (FIELD), True)
+
+# define MINUTES(FIELD,NAME) \
+ w = name_to_widget (s, (NAME)); \
+ hack_time_text (s, gtk_entry_get_text (GTK_ENTRY (w)), (FIELD), False)
+
+# define CHECKBOX(FIELD,NAME) \
+ w = name_to_widget (s, (NAME)); \
+ (FIELD) = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))
+
+# define PATHNAME(FIELD,NAME) \
+ w = name_to_widget (s, (NAME)); \
+ (FIELD) = normalize_directory (gtk_entry_get_text (GTK_ENTRY (w)))
+
+ MINUTES (&p2->timeout, "timeout_spinbutton");
+ MINUTES (&p2->cycle, "cycle_spinbutton");
+ CHECKBOX (p2->lock_p, "lock_button");
+ MINUTES (&p2->lock_timeout, "lock_spinbutton");
+
+ CHECKBOX (p2->dpms_enabled_p, "dpms_button");
+ MINUTES (&p2->dpms_standby, "dpms_standby_spinbutton");
+ MINUTES (&p2->dpms_suspend, "dpms_suspend_spinbutton");
+ MINUTES (&p2->dpms_off, "dpms_off_spinbutton");
+
+ CHECKBOX (p2->grab_desktop_p, "grab_desk_button");
+ CHECKBOX (p2->grab_video_p, "grab_video_button");
+ CHECKBOX (p2->random_image_p, "grab_image_button");
+ PATHNAME (p2->image_directory, "image_text");
+
+ CHECKBOX (p2->verbose_p, "verbose_button");
+ CHECKBOX (p2->capture_stderr_p, "capture_button");
+ CHECKBOX (p2->splash_p, "splash_button");
+
+ CHECKBOX (p2->install_cmap_p, "install_button");
+ CHECKBOX (p2->fade_p, "fade_button");
+ CHECKBOX (p2->unfade_p, "unfade_button");
+ SECONDS (&p2->fade_seconds, "fade_spinbutton");
+
+# undef SECONDS
+# undef MINUTES
+# undef CHECKBOX
+# undef PATHNAME
+
+ /* Warn if the image directory doesn't exist.
+ */
+ if (p2->image_directory &&
+ *p2->image_directory &&
+ !directory_p (p2->image_directory))
+ {
+ char b[255];
+ sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n",
+ p2->image_directory);
+ warning_dialog (s->toplevel_widget, b, False, 100);
+ }
+
+
+ /* Map the mode menu to `saver_mode' enum values. */
+ {
+ GtkOptionMenu *opt = GTK_OPTION_MENU (name_to_widget (s, "mode_menu"));
+ GtkMenu *menu = GTK_MENU (gtk_option_menu_get_menu (opt));
+ GtkWidget *selected = gtk_menu_get_active (menu);
+ GList *kids = gtk_container_children (GTK_CONTAINER (menu));
+ int menu_elt = g_list_index (kids, (gpointer) selected);
+ if (menu_elt < 0 || menu_elt >= countof(mode_menu_order)) abort();
+ p2->mode = mode_menu_order[menu_elt];
+ }
+
+ if (p2->mode == ONE_HACK)
+ {
+ int list_elt = selected_list_element (s);
+ p2->selected_hack = (list_elt >= 0
+ ? s->list_elt_to_hack_number[list_elt]
+ : -1);
+ }
+
+# define COPY(field, name) \
+ if (p->field != p2->field) { \
+ changed = True; \
+ if (s->debug_p) \
+ fprintf (stderr, "%s: %s => %d\n", blurb(), name, p2->field); \
+ } \
+ p->field = p2->field
+
+ COPY(mode, "mode");
+ COPY(selected_hack, "selected_hack");
+
+ COPY(timeout, "timeout");
+ COPY(cycle, "cycle");
+ COPY(lock_p, "lock_p");
+ COPY(lock_timeout, "lock_timeout");
+
+ COPY(dpms_enabled_p, "dpms_enabled_p");
+ COPY(dpms_standby, "dpms_standby");
+ COPY(dpms_suspend, "dpms_suspend");
+ COPY(dpms_off, "dpms_off");
+
+ COPY(verbose_p, "verbose_p");
+ COPY(capture_stderr_p, "capture_stderr_p");
+ COPY(splash_p, "splash_p");
+
+ COPY(install_cmap_p, "install_cmap_p");
+ COPY(fade_p, "fade_p");
+ COPY(unfade_p, "unfade_p");
+ COPY(fade_seconds, "fade_seconds");
+
+ COPY(grab_desktop_p, "grab_desktop_p");
+ COPY(grab_video_p, "grab_video_p");
+ COPY(random_image_p, "random_image_p");
+
+# undef COPY
+
+ if (!p->image_directory ||
+ !p2->image_directory ||
+ strcmp(p->image_directory, p2->image_directory))
+ {
+ changed = True;
+ if (s->debug_p)
+ fprintf (stderr, "%s: image_directory => \"%s\"\n",
+ blurb(), p2->image_directory);
+ }
+ if (p->image_directory && p->image_directory != p2->image_directory)
+ free (p->image_directory);
+ p->image_directory = p2->image_directory;
+ p2->image_directory = 0;
+
+ populate_prefs_page (s);
+
+ if (changed)
+ {
+ Display *dpy = GDK_DISPLAY();
+ Bool enabled_p = (p->dpms_enabled_p && p->mode != DONT_BLANK);
+ sync_server_dpms_settings (dpy, enabled_p,
+ p->dpms_standby / 1000,
+ p->dpms_suspend / 1000,
+ p->dpms_off / 1000,
+ False);
+
+ changed = demo_write_init_file (s, p);
+ }
+
+ s->saving_p = False;
+ return changed;
+}
+
+
+/* Flush out any changes made in the popup dialog box (where changes
+ take place only when the OK button is clicked.)
+ */
+static Bool
+flush_popup_changes_and_save (state *s)
+{
+ Bool changed = False;
+ saver_preferences *p = &s->prefs;
+ int list_elt = selected_list_element (s);
+
+ GtkEntry *cmd = GTK_ENTRY (name_to_widget (s, "cmd_text"));
+ GtkCombo *vis = GTK_COMBO (name_to_widget (s, "visual_combo"));
+
+ const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
+ const char *command = gtk_entry_get_text (cmd);
+
+ char c;
+ unsigned long id;
+
+ if (s->saving_p) return False;
+ s->saving_p = True;
+
+ if (list_elt < 0)
+ goto DONE;
+
+ if (maybe_reload_init_file (s) != 0)
+ {
+ changed = True;
+ goto DONE;
+ }
+
+ /* Sanity-check and canonicalize whatever the user typed into the combo box.
+ */
+ if (!strcasecmp (visual, "")) visual = "";
+ else if (!strcasecmp (visual, "any")) visual = "";
+ else if (!strcasecmp (visual, "default")) visual = "Default";
+ else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
+ else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
+ else if (!strcasecmp (visual, "best")) visual = "Best";
+ else if (!strcasecmp (visual, "mono")) visual = "Mono";
+ else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
+ else if (!strcasecmp (visual, "gray")) visual = "Gray";
+ else if (!strcasecmp (visual, "grey")) visual = "Gray";
+ else if (!strcasecmp (visual, "color")) visual = "Color";
+ else if (!strcasecmp (visual, "gl")) visual = "GL";
+ else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
+ else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
+ else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
+ else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
+ else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
+ else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
+ else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
+ else if (1 == sscanf (visual, " %ld %c", &id, &c)) ;
+ else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
+ else
+ {
+ gdk_beep (); /* unparsable */
+ visual = "";
+ gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), _("Any"));
+ }
+
+ changed = flush_changes (s, list_elt, -1, command, visual);
+ if (changed)
+ {
+ changed = demo_write_init_file (s, p);
+
+ /* Do this to re-launch the hack if (and only if) the command line
+ has changed. */
+ populate_demo_window (s, selected_list_element (s));
+ }
+
+ DONE:
+ s->saving_p = False;
+ return changed;
+}
+
+
+void
+pref_changed_cb (GtkWidget *widget, gpointer user_data)
+{
+ state *s = global_state_kludge; /* I hate C so much... */
+ if (! s->initializing_p)
+ {
+ s->initializing_p = True;
+ flush_dialog_changes_and_save (s);
+ s->initializing_p = False;
+ }
+}
+
+gboolean
+pref_changed_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+ pref_changed_cb (widget, user_data);
+ return FALSE;
+}
+
+/* Callback on menu items in the "mode" options menu.
+ */
+void
+mode_menu_item_cb (GtkWidget *widget, gpointer user_data)
+{
+ state *s = (state *) user_data;
+ saver_preferences *p = &s->prefs;
+ GtkWidget *list = name_to_widget (s, "list");
+ int list_elt;
+
+ GList *menu_items = gtk_container_children (GTK_CONTAINER (widget->parent));
+ int menu_index = 0;
+ saver_mode new_mode;
+ int old_selected = p->selected_hack;
+
+ while (menu_items)
+ {
+ if (menu_items->data == widget)
+ break;
+ menu_index++;
+ menu_items = menu_items->next;
+ }
+ if (!menu_items) abort();
+
+ new_mode = mode_menu_order[menu_index];
+
+ /* Keep the same list element displayed as before; except if we're
+ switching *to* "one screensaver" mode from any other mode, scroll
+ to and select "the one".
+ */
+ list_elt = -1;
+ if (new_mode == ONE_HACK)
+ list_elt = (p->selected_hack >= 0
+ ? s->hack_number_to_list_elt[p->selected_hack]
+ : -1);
+
+ if (list_elt < 0)
+ list_elt = selected_list_element (s);
+
+ {
+ saver_mode old_mode = p->mode;
+ p->mode = new_mode;
+ populate_demo_window (s, list_elt);
+ force_list_select_item (s, list, list_elt, True);
+ p->mode = old_mode; /* put it back, so the init file gets written */
+ }
+
+ pref_changed_cb (widget, user_data);
+
+ if (old_selected != p->selected_hack)
+ abort(); /* dammit, not again... */
+}
+
+
+void
+switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page,
+ gint page_num, gpointer user_data)
+{
+ state *s = global_state_kludge; /* I hate C so much... */
+ pref_changed_cb (GTK_WIDGET (notebook), user_data);
+
+ /* If we're switching to page 0, schedule the current hack to be run.
+ Otherwise, schedule it to stop. */
+ if (page_num == 0)
+ populate_demo_window (s, selected_list_element (s));
+ else
+ schedule_preview (s, 0);
+}
+
+#ifdef HAVE_GTK2
+static void
+list_activated_cb (GtkTreeView *list,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer data)
+{
+ state *s = data;
+ char *str;
+ int list_elt;
+
+ g_return_if_fail (!gdk_pointer_is_grabbed ());
+
+ str = gtk_tree_path_to_string (path);
+ list_elt = strtol (str, NULL, 10);
+ g_free (str);
+
+ if (list_elt >= 0)
+ run_hack (s, list_elt, True);
+}
+
+static void
+list_select_changed_cb (GtkTreeSelection *selection, gpointer data)
+{
+ state *s = (state *)data;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ char *str;
+ int list_elt;
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ path = gtk_tree_model_get_path (model, &iter);
+ str = gtk_tree_path_to_string (path);
+ list_elt = strtol (str, NULL, 10);
+
+ gtk_tree_path_free (path);
+ g_free (str);
+
+ populate_demo_window (s, list_elt);
+ flush_dialog_changes_and_save (s);
+}
+
+#else /* !HAVE_GTK2 */
+
+static time_t last_doubleclick_time = 0; /* FMH! This is to suppress the
+ list_select_cb that comes in
+ *after* we've double-clicked.
+ */
+
+static gint
+list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
+ gpointer data)
+{
+ state *s = (state *) data;
+ if (event->type == GDK_2BUTTON_PRESS)
+ {
+ GtkList *list = GTK_LIST (name_to_widget (s, "list"));
+ int list_elt = gtk_list_child_position (list, GTK_WIDGET (button));
+
+ last_doubleclick_time = time ((time_t *) 0);
+
+ if (list_elt >= 0)
+ run_hack (s, list_elt, True);
+ }
+
+ return FALSE;
+}
+
+
+static void
+list_select_cb (GtkList *list, GtkWidget *child, gpointer data)
+{
+ state *s = (state *) data;
+ time_t now = time ((time_t *) 0);
+
+ if (now >= last_doubleclick_time + 2)
+ {
+ int list_elt = gtk_list_child_position (list, GTK_WIDGET (child));
+ populate_demo_window (s, list_elt);
+ flush_dialog_changes_and_save (s);
+ }
+}
+
+static void
+list_unselect_cb (GtkList *list, GtkWidget *child, gpointer data)
+{
+ state *s = (state *) data;
+ populate_demo_window (s, -1);
+ flush_dialog_changes_and_save (s);
+}
+
+#endif /* !HAVE_GTK2 */