/* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
- * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-1999 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
# include "xmu.h"
#endif
-
-
#include <gtk/gtk.h>
+#ifdef HAVE_CRAPPLET
+# include <gnome.h>
+# include <capplet-widget.h>
+#endif
+
extern Display *gdk_display;
#include "version.h"
char *progclass = "XScreenSaver";
XrmDatabase db;
+static Bool crapplet_p = False;
+static Bool initializing_p;
+static GtkWidget *toplevel_widget;
+
typedef struct {
saver_preferences *a, *b;
} prefs_pair;
static void *global_prefs_pair; /* I hate C so much... */
-
-
char *blurb (void) { return progname; }
-static void run_hack (int which);
-
static char *short_version = 0;
Atom XA_VROOT;
Atom XA_ACTIVATE, XA_BLANK, XA_LOCK, XA_RESTART, XA_EXIT;
-
static void populate_demo_window (GtkWidget *toplevel,
int which, prefs_pair *pair);
static void populate_prefs_page (GtkWidget *top, prefs_pair *pair);
-
+static int apply_changes_and_save (GtkWidget *widget);
+static int maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair);
+static void await_xscreensaver (GtkWidget *widget);
\f
/* Some random utility functions
static GtkWidget *
name_to_widget (GtkWidget *widget, const char *name)
{
- while (1)
- {
- GtkWidget *parent = (GTK_IS_MENU (widget)
- ? gtk_menu_get_attach_widget (GTK_MENU (widget))
- : widget->parent);
- if (parent)
- widget = parent;
- else
- break;
- }
- return (GtkWidget *) gtk_object_get_data (GTK_OBJECT (widget), name);
+ return (GtkWidget *) gtk_object_get_data (GTK_OBJECT(toplevel_widget), name);
}
-
/* Why this behavior isn't automatic in *either* toolkit, I'll never know.
Takes a scroller, viewport, or list as an argument.
*/
kids; kids = kids->next)
nkids++;
- adj = gtk_scrolled_window_get_vadjustment (scroller);
+ adj = gtk_scrolled_window_get_vadjustment (scroller);
gdk_window_get_geometry (GTK_WIDGET(vp)->window,
&ignore, &ignore, &ignore, &parent_h, &ignore);
ratio_t = ((double) child_y) / ((double) children_h);
ratio_b = ((double) child_y + child_h) / ((double) children_h);
+ if (adj->upper == 0.0) /* no items in list */
+ return;
+
if (ratio_t < (adj->value / adj->upper) ||
ratio_b > ((adj->value + adj->page_size) / adj->upper))
{
}
}
-
static void
-warning_dialog_dismiss_cb (GtkButton *button, gpointer user_data)
+warning_dialog_dismiss_cb (GtkWidget *widget, gpointer user_data)
{
GtkWidget *shell = GTK_WIDGET (user_data);
while (shell->parent)
}
+void restart_menu_cb (GtkWidget *widget, gpointer user_data);
+
+static void warning_dialog_restart_cb (GtkWidget *widget, gpointer user_data)
+{
+ restart_menu_cb (widget, user_data);
+ warning_dialog_dismiss_cb (widget, user_data);
+}
+
static void
-warning_dialog (GtkWidget *parent, const char *message, int center)
+warning_dialog (GtkWidget *parent, const char *message,
+ Boolean restart_button_p, int center)
{
char *msg = strdup (message);
char *head;
GtkWidget *dialog = gtk_dialog_new ();
GtkWidget *label = 0;
GtkWidget *ok = 0;
+ GtkWidget *cancel = 0;
int i = 0;
while (parent->parent)
sprintf (name, "label%d", i++);
{
+#if 0
char buf[255];
+#endif
label = gtk_label_new (head);
+#if 0
sprintf (buf, "warning_dialog.%s.font", name);
GTK_WIDGET (label)->style = gtk_style_copy (GTK_WIDGET (label)->style);
GTK_WIDGET (label)->style->font =
gdk_font_load (get_string_resource (buf, "Dialog.Label.Font"));
+#endif
if (center <= 0)
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
label, TRUE, TRUE, 0);
- ok = gtk_button_new_with_label (
- get_string_resource ("warning_dialog.ok.label",
- "warning_dialog.Button.Label"));
+ ok = gtk_button_new_with_label ("OK");
gtk_container_add (GTK_CONTAINER (label), ok);
+ if (restart_button_p)
+ {
+ cancel = gtk_button_new_with_label ("Cancel");
+ gtk_container_add (GTK_CONTAINER (label), cancel);
+ }
+
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
gtk_window_set_title (GTK_WINDOW (dialog), progclass);
gtk_widget_show (ok);
+ if (cancel)
+ gtk_widget_show (cancel);
gtk_widget_show (label);
gtk_widget_show (dialog);
/* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
- gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
- GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
- (gpointer) dialog);
+ if (restart_button_p)
+ {
+ gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
+ GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
+ (gpointer) dialog);
+ gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
+ GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
+ (gpointer) dialog);
+ }
+ else
+ {
+ gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
+ GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
+ (gpointer) dialog);
+ }
gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
GTK_WIDGET (parent)->window);
static void
-run_hack (int which)
+run_cmd (GtkWidget *widget, Atom command, int arg)
{
+ char *err = 0;
int status;
- if (which < 0) return;
- status = xscreensaver_command (gdk_display, XA_DEMO, which + 1, False);
+
+ apply_changes_and_save (widget);
+ status = xscreensaver_command (gdk_display, command, arg, False, &err);
if (status < 0)
{
char buf [255];
- sprintf (buf,
- "Error:\n\n"
- "The DEMO %d command failed (%d).\n", which + 1, status);
-#if 0
- warning_dialog (GTK_WIDGET (menuitem), buf, 1);
-#endif
+ if (err)
+ sprintf (buf, "Error:\n\n%s", err);
+ else
+ strcpy (buf, "Unknown error!");
+ warning_dialog (widget, buf, False, 100);
+ }
+ if (err) free (err);
+}
+
+
+static void
+run_hack (GtkWidget *widget, int which, Bool report_errors_p)
+{
+ if (which < 0) return;
+ apply_changes_and_save (widget);
+ if (report_errors_p)
+ run_cmd (widget, XA_DEMO, which + 1);
+ else
+ {
+ char *s = 0;
+ xscreensaver_command (gdk_display, XA_DEMO, which + 1, False, &s);
+ if (s) free (s);
}
}
void
exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
+ apply_changes_and_save (GTK_WIDGET (menuitem));
gtk_main_quit ();
}
static void
wm_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
{
- exit_menu_cb (NULL, NULL);
+ apply_changes_and_save (widget);
+ gtk_main_quit ();
}
/* #### */
warning_dialog (GTK_WIDGET (menuitem),
"Error:\n\n"
- "cut unimplemented\n", 1);
+ "cut unimplemented\n", False, 1);
}
/* #### */
warning_dialog (GTK_WIDGET (menuitem),
"Error:\n\n"
- "copy unimplemented\n", 1);
+ "copy unimplemented\n", False, 1);
}
/* #### */
warning_dialog (GTK_WIDGET (menuitem),
"Error:\n\n"
- "paste unimplemented\n", 1);
+ "paste unimplemented\n", False, 1);
}
s, s2);
free (s);
- warning_dialog (GTK_WIDGET (menuitem), buf, 100);
+ warning_dialog (GTK_WIDGET (menuitem), buf, False, 100);
}
{
warning_dialog (GTK_WIDGET (menuitem),
"Error:\n\n"
- "No Help URL has been specified.\n", 100);
+ "No Help URL has been specified.\n", False, 100);
return;
}
void
activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
- int status = xscreensaver_command (gdk_display, XA_ACTIVATE, 0, False);
- if (status < 0)
- {
- char buf [255];
- sprintf (buf,
- "Error:\n\n"
- "The ACTIVATE command failed (%d).\n", status);
- warning_dialog (GTK_WIDGET (menuitem), buf, 100);
- }
+ run_cmd (GTK_WIDGET (menuitem), XA_ACTIVATE, 0);
}
void
lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
- int status = xscreensaver_command (gdk_display, XA_LOCK, 0, False);
- if (status < 0)
- {
- char buf [255];
- sprintf (buf,
- "Error:\n\n"
- "The LOCK command failed (%d).\n", status);
- warning_dialog (GTK_WIDGET (menuitem), buf, 100);
- }
+ run_cmd (GTK_WIDGET (menuitem), XA_LOCK, 0);
}
void
kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
- int status = xscreensaver_command (gdk_display, XA_EXIT, 0, False);
- if (status < 0)
- {
- char buf [255];
- sprintf (buf,
- "Error:\n\n"
- "The EXIT command failed (%d).\n", status);
- warning_dialog (GTK_WIDGET (menuitem), buf, 100);
- }
+ run_cmd (GTK_WIDGET (menuitem), XA_EXIT, 0);
}
void
-restart_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
+restart_menu_cb (GtkWidget *widget, gpointer user_data)
{
#if 0
- int status = xscreensaver_command (gdk_display, XA_RESTART, 0, False);
- if (status < 0)
- {
- char buf [255];
- sprintf (buf,
- "Error:\n\n"
- "The RESTART command failed (%d).\n", status);
- warning_dialog (GTK_WIDGET (menuitem), buf, 100);
- }
+ run_cmd (GTK_WIDGET (widget), XA_RESTART, 0);
#else
- xscreensaver_command (gdk_display, XA_EXIT, 0, False);
+ apply_changes_and_save (GTK_WIDGET (widget));
+ xscreensaver_command (gdk_display, XA_EXIT, 0, False, NULL);
sleep (1);
system ("xscreensaver -nosplash &");
#endif
+
+ await_xscreensaver (GTK_WIDGET (widget));
}
+static void
+await_xscreensaver (GtkWidget *widget)
+{
+ int countdown = 5;
+
+ Display *dpy = gdk_display;
+ /* GtkWidget *dialog = 0;*/
+ char *rversion = 0;
+
+ while (!rversion && (--countdown > 0))
+ {
+ /* Check for the version of the running xscreensaver... */
+ server_xscreensaver_version (dpy, &rversion, 0, 0);
+
+ /* If it's not there yet, wait a second... */
+ sleep (1);
+ }
+
+/* if (dialog) gtk_widget_destroy (dialog);*/
+
+ if (rversion)
+ {
+ /* Got it. */
+ free (rversion);
+ }
+ else
+ {
+ /* Timed out, no screensaver running. */
+
+ char buf [1024];
+ Bool root_p = (geteuid () == 0);
+
+ strcpy (buf,
+ "Error:\n\n"
+ "The xscreensaver daemon did not start up properly.\n"
+ "\n");
+
+ if (root_p)
+ strcat (buf,
+ "You are running as root. This usually means that xscreensaver\n"
+ "was unable to contact your X server because access control is\n"
+ "turned on. Try running this command:\n"
+ "\n"
+ " xhost +localhost\n"
+ "\n"
+ "and then selecting `File / Restart Daemon'.\n"
+ "\n"
+ "Note that turning off access control will allow anyone logged\n"
+ "on to this machine to access your screen, which might be\n"
+ "considered a security problem. Please read the xscreensaver\n"
+ "manual and FAQ for more information.\n"
+ "\n"
+ "You shouldn't run X as root. Instead, you should log in as a\n"
+ "normal user, and `su' as necessary.");
+ else
+ strcat (buf, "Please check your $PATH and permissions.");
+
+ warning_dialog (widget, buf, False, 1);
+ }
+}
+
+
+static int _selected_hack_number = -1;
static int
selected_hack_number (GtkWidget *toplevel)
{
+#if 0
GtkViewport *vp = GTK_VIEWPORT (name_to_widget (toplevel, "viewport"));
GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
GList *slist = list_widget->selection;
? gtk_list_child_position (list_widget, GTK_WIDGET (selected))
: -1);
return which;
+#else
+ return _selected_hack_number;
+#endif
}
-void
-apply_this_cb (GtkButton *button, gpointer user_data)
+static int
+demo_write_init_file (GtkWidget *widget, saver_preferences *p)
+{
+ if (!write_init_file (p, short_version, False))
+ return 0;
+ else
+ {
+ const char *f = init_file_name();
+ if (!f || !*f)
+ warning_dialog (widget,
+ "Error:\n\nCouldn't determine init file name!\n",
+ False, 100);
+ else
+ {
+ char *b = (char *) malloc (strlen(f) + 1024);
+ sprintf (b, "Error:\n\nCouldn't write %s\n", f);
+ warning_dialog (widget, b, False, 100);
+ free (b);
+ }
+ return -1;
+ }
+}
+
+
+static int
+apply_changes_and_save_1 (GtkWidget *widget)
{
/* prefs_pair *pair = (prefs_pair *) client_data; */
prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
-
saver_preferences *p = pair->a;
GtkList *list_widget =
- GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
- int which = selected_hack_number (GTK_WIDGET (button));
+ GTK_LIST (name_to_widget (widget, "list"));
+ int which = selected_hack_number (widget);
- GtkEntry *cmd = GTK_ENTRY (name_to_widget (GTK_WIDGET (button), "cmd_text"));
+ GtkEntry *cmd = GTK_ENTRY (name_to_widget (widget, "cmd_text"));
GtkToggleButton *enabled =
- GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET (button), "enabled"));
- GtkCombo *vis = GTK_COMBO (name_to_widget (GTK_WIDGET (button),
- "visual_combo"));
+ GTK_TOGGLE_BUTTON (name_to_widget (widget, "enabled"));
+ GtkCombo *vis = GTK_COMBO (name_to_widget (widget, "visual_combo"));
Bool enabled_p = gtk_toggle_button_get_active (enabled);
const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
char c;
unsigned long id;
- if (which < 0) return;
+ if (which < 0) return -1;
+
+ if (maybe_reload_init_file (widget, pair) != 0)
+ return 1;
/* Sanity-check and canonicalize whatever the user typed into the combo box.
*/
- if (!strcasecmp (visual, "any")) visual = "";
- if (!strcasecmp (visual, "default")) visual = "Default";
+ 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";
gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");
}
- p->screenhacks[which]->enabled_p = enabled_p;
- if (p->screenhacks[which]->visual)
- free (p->screenhacks[which]->visual);
- if (p->screenhacks[which]->command)
- free (p->screenhacks[which]->command);
- p->screenhacks[which]->visual = strdup (visual);
- p->screenhacks[which]->command = strdup (command);
-
ensure_selected_item_visible (GTK_WIDGET (list_widget));
- write_init_file (p, short_version);
+ if (!p->screenhacks[which]->visual)
+ p->screenhacks[which]->visual = strdup ("");
+ if (!p->screenhacks[which]->command)
+ p->screenhacks[which]->command = strdup ("");
+
+ if (p->screenhacks[which]->enabled_p != enabled_p ||
+ !!strcasecmp (p->screenhacks[which]->visual, visual) ||
+ !!strcasecmp (p->screenhacks[which]->command, command))
+ {
+ /* Something was changed -- store results into the struct,
+ and write the file.
+ */
+ free (p->screenhacks[which]->visual);
+ free (p->screenhacks[which]->command);
+ p->screenhacks[which]->visual = strdup (visual);
+ p->screenhacks[which]->command = strdup (command);
+ p->screenhacks[which]->enabled_p = enabled_p;
+
+ return demo_write_init_file (widget, p);
+ }
+
+ /* No changes made */
+ return 0;
+}
+
+void prefs_ok_cb (GtkButton *button, gpointer user_data);
+
+static int
+apply_changes_and_save (GtkWidget *widget)
+{
+ prefs_ok_cb ((GtkButton *) widget, 0);
+ return apply_changes_and_save_1 (widget);
}
{
int which = selected_hack_number (GTK_WIDGET (button));
if (which < 0) return;
- apply_this_cb (button, user_data);
- run_hack (which);
+ if (0 == apply_changes_and_save (GTK_WIDGET (button)))
+ run_hack (GTK_WIDGET (button), which, True);
}
void
-cancel_this_cb (GtkButton *button, gpointer user_data)
+manual_cb (GtkButton *button, gpointer user_data)
{
/* prefs_pair *pair = (prefs_pair *) client_data; */
prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
+ saver_preferences *p = pair->a;
GtkList *list_widget =
GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
int which = selected_hack_number (GTK_WIDGET (button));
+ char *name, *name2, *cmd, *s;
if (which < 0) return;
+ apply_changes_and_save (GTK_WIDGET (button));
ensure_selected_item_visible (GTK_WIDGET (list_widget));
- populate_demo_window (GTK_WIDGET (button), which, pair);
+
+ name = strdup (p->screenhacks[which]->command);
+ name2 = name;
+ while (isspace (*name2)) name2++;
+ s = name2;
+ while (*s && !isspace (*s)) s++;
+ *s = 0;
+ s = strrchr (name2, '/');
+ if (s) name = s+1;
+
+ cmd = get_string_resource ("manualCommand", "ManualCommand");
+ if (cmd)
+ {
+ char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
+ strcpy (cmd2, "( ");
+ sprintf (cmd2 + strlen (cmd2),
+ cmd,
+ name2, name2, name2, name2);
+ strcat (cmd2, " ) &");
+ system (cmd2);
+ free (cmd2);
+ }
+ else
+ {
+ warning_dialog (GTK_WIDGET (button),
+ "Error:\n\nno `manualCommand' resource set.",
+ False, 100);
+ }
+
+ free (name);
}
if (which >= p->screenhacks_count)
which = 0;
+ apply_changes_and_save (GTK_WIDGET (button));
gtk_list_select_item (GTK_LIST (list_widget), which);
ensure_selected_item_visible (GTK_WIDGET (list_widget));
populate_demo_window (GTK_WIDGET (button), which, pair);
- run_hack (which);
+ run_hack (GTK_WIDGET (button), which, False);
}
if (which < 0)
which = p->screenhacks_count - 1;
+ apply_changes_and_save (GTK_WIDGET (button));
gtk_list_select_item (GTK_LIST (list_widget), which);
ensure_selected_item_visible (GTK_WIDGET (list_widget));
populate_demo_window (GTK_WIDGET (button), which, pair);
- run_hack (which);
+ run_hack (GTK_WIDGET (button), which, False);
}
this parses the text, and does error checking.
*/
static void
-hack_time_text (const char *line, Time *store, Bool sec_p)
+hack_time_text (GtkWidget *widget, const char *line, Time *store, Bool sec_p)
{
if (*line)
{
value = parse_time ((char *) line, sec_p, True);
value *= 1000; /* Time measures in microseconds */
if (value < 0)
- /* gdk_beep () */;
+ {
+ char b[255];
+ sprintf (b,
+ "Error:\n\n"
+ "Unparsable time format: \"%s\"\n",
+ line);
+ warning_dialog (widget, b, False, 100);
+ }
else
*store = value;
}
saver_preferences *p = pair->a;
saver_preferences *p2 = pair->b;
+ Bool changed = False;
# define SECONDS(field, name) \
- hack_time_text (gtk_entry_get_text (\
+ hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
(field), \
True)
# define MINUTES(field, name) \
- hack_time_text (gtk_entry_get_text (\
+ hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
(field), \
False)
if (! *line) \
; \
else if (sscanf (line, "%u%c", &value, &c) != 1) \
- gdk_beep(); \
+ { \
+ char b[255]; \
+ sprintf (b, "Error:\n\n" "Not an integer: \"%s\"\n", line); \
+ warning_dialog (GTK_WIDGET (button), b, False, 100); \
+ } \
else \
*(field) = value; \
} while(0)
+# define CHECKBOX(field, name) \
+ field = gtk_toggle_button_get_active (\
+ GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET(button), (name))))
+
MINUTES (&p2->timeout, "timeout_text");
MINUTES (&p2->cycle, "cycle_text");
SECONDS (&p2->fade_seconds, "fade_text");
INTEGER (&p2->fade_ticks, "ticks_text");
MINUTES (&p2->lock_timeout, "lock_text");
SECONDS (&p2->passwd_timeout, "pass_text");
-
-#undef SECONDS
-#undef MINUTES
-#undef INTEGER
-
- p->timeout = p2->timeout;
- p->cycle = p2->cycle;
- p->lock_timeout = p2->lock_timeout;
- p->passwd_timeout = p2->passwd_timeout;
- p->fade_seconds = p2->fade_seconds;
- p->fade_ticks = p2->fade_ticks;
- p->verbose_p = p2->verbose_p;
- p->install_cmap_p = p2->install_cmap_p;
- p->fade_p = p2->fade_p;
- p->unfade_p = p2->unfade_p;
- p->lock_p = p2->lock_p;
+ CHECKBOX (p2->verbose_p, "verbose_button");
+ CHECKBOX (p2->install_cmap_p, "install_button");
+ CHECKBOX (p2->fade_p, "fade_button");
+ CHECKBOX (p2->unfade_p, "unfade_button");
+ CHECKBOX (p2->lock_p, "lock_button");
+
+# undef SECONDS
+# undef MINUTES
+# undef INTEGER
+# undef CHECKBOX
+
+# define COPY(field) \
+ if (p->field != p2->field) changed = True; \
+ p->field = p2->field
+
+ COPY(timeout);
+ COPY(cycle);
+ COPY(lock_timeout);
+ COPY(passwd_timeout);
+ COPY(fade_seconds);
+ COPY(fade_ticks);
+ COPY(verbose_p);
+ COPY(install_cmap_p);
+ COPY(fade_p);
+ COPY(unfade_p);
+ COPY(lock_p);
+# undef COPY
populate_prefs_page (GTK_WIDGET (button), pair);
- write_init_file (p, short_version);
+ if (changed)
+ demo_write_init_file (GTK_WIDGET (button), p);
}
}
+void
+pref_changed_cb (GtkButton *button, gpointer user_data)
+{
+ if (! initializing_p)
+ apply_changes_and_save (GTK_WIDGET (button));
+}
+
+
static gint
list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
gpointer client_data)
int which = gtk_list_child_position (list, GTK_WIDGET (button));
if (which >= 0)
- run_hack (which);
+ run_hack (GTK_WIDGET (button), which, True);
}
return FALSE;
prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
int which = gtk_list_child_position (list, GTK_WIDGET (child));
+ apply_changes_and_save (GTK_WIDGET (list));
populate_demo_window (GTK_WIDGET (list), which, pair);
}
/* prefs_pair *pair = (prefs_pair *) client_data; */
prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
+ apply_changes_and_save (GTK_WIDGET (list));
populate_demo_window (GTK_WIDGET (list), -1, pair);
}
+
+static int updating_enabled_cb = 0; /* kludge to make sure that enabled_cb
+ is only run by user action, not by
+ program action. */
+
+/* Called when the checkboxes that are in the left column of the
+ scrolling list are clicked. This both populates the right pane
+ (just as clicking on the label (really, listitem) does) and
+ also syncs this checkbox with the right pane Enabled checkbox.
+ */
+static void
+list_checkbox_cb (GtkWidget *cb, gpointer client_data)
+{
+ prefs_pair *pair = (prefs_pair *) client_data;
+
+ GtkWidget *line_hbox = GTK_WIDGET (cb)->parent;
+ GtkWidget *line = GTK_WIDGET (line_hbox)->parent;
+
+ GtkList *list = GTK_LIST (GTK_WIDGET (line)->parent);
+ GtkViewport *vp = GTK_VIEWPORT (GTK_WIDGET (list)->parent);
+ GtkScrolledWindow *scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
+ GtkAdjustment *adj;
+ double scroll_top;
+
+ GtkToggleButton *enabled =
+ GTK_TOGGLE_BUTTON (name_to_widget (cb, "enabled"));
+
+ int which = gtk_list_child_position (list, line);
+
+ /* remember previous scroll position of the top of the list */
+ adj = gtk_scrolled_window_get_vadjustment (scroller);
+ scroll_top = adj->value;
+
+ apply_changes_and_save (GTK_WIDGET (list));
+ gtk_list_select_item (list, which);
+ /* ensure_selected_item_visible (GTK_WIDGET (list)); */
+ populate_demo_window (GTK_WIDGET (list), which, pair);
+
+ updating_enabled_cb++;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (enabled),
+ GTK_TOGGLE_BUTTON (cb)->active);
+ updating_enabled_cb--;
+
+ /* restore the previous scroll position of the top of the list.
+ this is weak, but I don't really know why it's moving... */
+ gtk_adjustment_set_value (adj, scroll_top);
+}
+
+
+/* Called when the right pane Enabled checkbox is clicked. This syncs
+ the corresponding checkbox inside the scrolling list to the state
+ of this checkbox.
+ */
+void
+enabled_cb (GtkWidget *cb, gpointer client_data)
+{
+ int which = selected_hack_number (cb);
+
+ if (updating_enabled_cb) return;
+
+ if (which != -1)
+ {
+ GtkList *list = GTK_LIST (name_to_widget (cb, "list"));
+ GList *kids = GTK_LIST (list)->children;
+ GtkWidget *line = GTK_WIDGET (g_list_nth_data (kids, which));
+ GtkWidget *line_hbox = GTK_WIDGET (GTK_BIN (line)->child);
+ GtkWidget *line_check =
+ GTK_WIDGET (gtk_container_children (GTK_CONTAINER (line_hbox))->data);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (line_check),
+ GTK_TOGGLE_BUTTON (cb)->active);
+ }
+}
+
\f
/* Populating the various widgets
*/
static void
scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
{
+ saver_preferences *p = pair->a;
Atom type;
int format;
unsigned long nitems, bytesafter;
return;
list = GTK_LIST (name_to_widget (toplevel, "list"));
- gtk_list_select_item (list, which);
- ensure_selected_item_visible (GTK_WIDGET (list));
- populate_demo_window (toplevel, which, pair);
+ apply_changes_and_save (toplevel);
+ if (which < p->screenhacks_count)
+ {
+ gtk_list_select_item (list, which);
+ ensure_selected_item_visible (GTK_WIDGET (list));
+ populate_demo_window (toplevel, which, pair);
+ }
}
screenhack **hacks = p->screenhacks;
screenhack **h;
- for (h = hacks; *h; h++)
+ for (h = hacks; h && *h; h++)
{
+ /* A GtkList must contain only GtkListItems, but those can contain
+ an arbitrary widget. We add an Hbox, and inside that, a Checkbox
+ and a Label. We handle single and double click events on the
+ line itself, for clicking on the text, but the interior checkbox
+ also handles its own events.
+ */
GtkWidget *line;
+ GtkWidget *line_hbox;
+ GtkWidget *line_check;
+ GtkWidget *line_label;
+
char *pretty_name = (h[0]->name
? strdup (h[0]->name)
: make_pretty_name (h[0]->command));
- line = gtk_list_item_new_with_label (pretty_name);
+ line = gtk_list_item_new ();
+ line_hbox = gtk_hbox_new (FALSE, 0);
+ line_check = gtk_check_button_new ();
+ line_label = gtk_label_new (pretty_name);
+
+ gtk_container_add (GTK_CONTAINER (line), line_hbox);
+ gtk_box_pack_start (GTK_BOX (line_hbox), line_check, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (line_hbox), line_label, FALSE, FALSE, 0);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (line_check),
+ h[0]->enabled_p);
+ gtk_label_set_justify (GTK_LABEL (line_label), GTK_JUSTIFY_LEFT);
+
+ gtk_widget_show (line_check);
+ gtk_widget_show (line_label);
+ gtk_widget_show (line_hbox);
+ gtk_widget_show (line);
+
free (pretty_name);
gtk_container_add (GTK_CONTAINER (list), line);
gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
GTK_SIGNAL_FUNC (list_doubleclick_cb),
(gpointer) pair);
+
+ gtk_signal_connect (GTK_OBJECT (line_check), "toggled",
+ GTK_SIGNAL_FUNC (list_checkbox_cb),
+ (gpointer) pair);
+
#if 0 /* #### */
GTK_WIDGET (GTK_BIN(line)->child)->style =
gtk_style_copy (GTK_WIDGET (text_line)->style);
{
const char *names[] = { "cmd_label", "cmd_text", "enabled",
"visual", "visual_combo",
- "demo", "apply", "cancel" };
+ "demo", "manual" };
int i;
for (i = 0; i < countof(names); i++)
{
"+ c #D6D6D6",
"@ c #000000",
+ " ",
" ------------- ",
" -+++++++++++@ ",
" -+++++++++@ ",
};
static void
-pixmapify_buttons (GtkWidget *toplevel)
+pixmapify_button (GtkWidget *toplevel, int down_p)
{
GdkPixmap *pixmap;
GdkBitmap *mask;
GtkStyle *style;
GtkWidget *w;
- w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "next"));
+ w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel),
+ (down_p ? "next" : "prev")));
style = gtk_widget_get_style (w);
mask = 0;
pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
&style->bg[GTK_STATE_NORMAL],
- (gchar **) down_arrow_xpm);
+ (down_p
+ ? (gchar **) down_arrow_xpm
+ : (gchar **) up_arrow_xpm));
pixmapwid = gtk_pixmap_new (pixmap, mask);
gtk_widget_show (pixmapwid);
gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
gtk_container_add (GTK_CONTAINER (w), pixmapwid);
+}
- w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "prev"));
- style = gtk_widget_get_style (w);
- mask = 0;
- pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
- &style->bg[GTK_STATE_NORMAL],
- (gchar **) up_arrow_xpm);
- pixmapwid = gtk_pixmap_new (pixmap, mask);
- gtk_widget_show (pixmapwid);
- gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
- gtk_container_add (GTK_CONTAINER (w), pixmapwid);
+static void
+map_next_button_cb (GtkWidget *w, gpointer user_data)
+{
+ pixmapify_button (w, 1);
+}
+
+static void
+map_prev_button_cb (GtkWidget *w, gpointer user_data)
+{
+ pixmapify_button (w, 0);
}
populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
{
saver_preferences *p = pair->a;
- screenhack *hack = (which >= 0 ? p->screenhacks[which] : 0);
+ screenhack *hack = (which >= 0 && which < p->screenhacks_count
+ ? p->screenhacks[which] : 0);
GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
gtk_label_set_text (doc, (doc_string ? doc_string : ""));
gtk_entry_set_text (cmd, (hack ? hack->command : ""));
gtk_entry_set_position (cmd, 0);
+
+ updating_enabled_cb++;
gtk_toggle_button_set_active (enabled, (hack ? hack->enabled_p : False));
+ updating_enabled_cb--;
+
gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry),
(hack
- ? (hack->visual && hack->visual
+ ? (hack->visual && *hack->visual
? hack->visual
: "Any")
: ""));
if (pretty_name) free (pretty_name);
if (doc_string) free (doc_string);
+
+ _selected_hack_number = which;
}
+static void
+widget_deleter (GtkWidget *widget, gpointer data)
+{
+ /* #### Well, I want to destroy these widgets, but if I do that, they get
+ referenced again, and eventually I get a SEGV. So instead of
+ destroying them, I'll just hide them, and leak a bunch of memory
+ every time the disk file changes. Go go go Gtk!
+
+ #### Ok, that's a lie, I get a crash even if I just hide the widget
+ and don't ever delete it. Fuck!
+ */
+#if 0
+ gtk_widget_destroy (widget);
+#else
+ gtk_widget_hide (widget);
+#endif
+}
+
+
+static int
+maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair)
+{
+ int status = 0;
+ saver_preferences *p = pair->a;
+
+ static Bool reentrant_lock = False;
+ if (reentrant_lock) return 0;
+ reentrant_lock = True;
+
+ if (init_file_changed_p (p))
+ {
+ const char *f = init_file_name();
+ char *b;
+ int which;
+ GtkList *list;
+
+ if (!f || !*f) return 0;
+ b = (char *) malloc (strlen(f) + 1024);
+ sprintf (b,
+ "Warning:\n\n"
+ "file \"%s\" has changed, reloading.\n",
+ f);
+ warning_dialog (widget, b, False, 100);
+ free (b);
+
+ load_init_file (p);
+
+ which = selected_hack_number (widget);
+ list = GTK_LIST (name_to_widget (widget, "list"));
+ gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL);
+ populate_hack_list (widget, pair);
+ gtk_list_select_item (list, which);
+ populate_prefs_page (widget, pair);
+ populate_demo_window (widget, which, pair);
+ ensure_selected_item_visible (GTK_WIDGET (list));
+
+ status = 1;
+ }
+
+ reentrant_lock = False;
+ return status;
+}
+
\f
/* The main demo-mode command loop.
sprintf (msg,
"Warning:\n\n"
"The XScreenSaver daemon doesn't seem to be running\n"
- "on display \"%s\". You can launch it by selecting\n"
- "`Restart Daemon' from the File menu, or by typing\n"
- "\"xscreensaver &\" in a shell.",
+ "on display \"%s\". Launch it now?",
d);
}
else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
"the same ~/.xscreensaver file, so %s isn't\n"
"going to work right.\n"
"\n"
- "Either re-run %s as \"%s\", or re-run\n"
- "xscreensaver as \"%s\" (which you can do by\n"
- "selecting `Restart Daemon' from the File menu.)\n",
+ "You should either re-run %s as \"%s\", or re-run\n"
+ "xscreensaver as \"%s\".\n"
+ "\n"
+ "Restart the xscreensaver daemon now?\n",
progname, luser, lhost,
d,
(ruser ? ruser : "???"), (rhost ? rhost : "???"),
"if they don't see the same ~%s/.xscreensaver file) then\n"
"%s won't work right.\n"
"\n"
- "You can restart the daemon on \"%s\" as \"%s\" by\n"
- "selecting `Restart Daemon' from the File menu.)",
+ "Restart the daemon on \"%s\" as \"%s\" now?\n",
progname, luser, lhost,
d,
(ruser ? ruser : "???"), (rhost ? rhost : "???"),
"Warning:\n\n"
"This is %s version %s.\n"
"But the xscreensaver managing display \"%s\"\n"
- "is version %s. This could cause problems.",
+ "is version %s. This could cause problems.\n"
+ "\n"
+ "Restart the xscreensaver daemon now?\n",
progname, short_version,
d,
rversion);
if (*msg)
- warning_dialog (parent, msg, 1);
+ warning_dialog (parent, msg, True, 1);
free (msg);
}
0
};
+#if 0
+#ifdef HAVE_CRAPPLET
+static struct poptOption crapplet_options[] = {
+ {NULL, '\0', 0, NULL, 0}
+};
+#endif /* HAVE_CRAPPLET */
+#endif /* 0 */
+
+#define USAGE() \
+ fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n", \
+ real_progname)
+
+
+static void
+map_window_cb (GtkWidget *w, gpointer user_data)
+{
+ Boolean oi = initializing_p;
+ initializing_p = True;
+ eschew_gtk_lossage (w);
+ ensure_selected_item_visible (GTK_WIDGET(name_to_widget(w, "list")));
+ initializing_p = oi;
+}
+
+
int
main (int argc, char **argv)
{
char *real_progname = argv[0];
char *s;
+ initializing_p = True;
+
s = strrchr (real_progname, '/');
if (s) real_progname = s+1;
!strncmp(argv[i], "-display", strlen(argv[i])))
argv[i] = "--display";
+
+ /* We need to parse this arg really early... Sigh. */
+ for (i = 1; i < argc; i++)
+ if (argv[i] &&
+ (!strcmp(argv[i], "--crapplet") ||
+ !strcmp(argv[i], "--capplet")))
+ {
+# ifdef HAVE_CRAPPLET
+ int j;
+ crapplet_p = True;
+ for (j = i; j < argc; j++) /* remove it from the list */
+ argv[j] = argv[j+1];
+ argc--;
+
+# else /* !HAVE_CRAPPLET */
+ fprintf (stderr, "%s: not compiled with --crapplet support\n",
+ real_progname[i]);
+ USAGE ();
+ exit (1);
+# endif /* !HAVE_CRAPPLET */
+ }
+
/* Let Gtk open the X connection, then initialize Xt to use that
- same connection. Doctor Frankenstein would be proud. */
- gtk_init (&argc, &argv);
+ same connection. Doctor Frankenstein would be proud.
+ */
+# ifdef HAVE_CRAPPLET
+ if (crapplet_p)
+ {
+ GnomeClient *client;
+ GnomeClientFlags flags = 0;
+
+ int init_results = gnome_capplet_init ("screensaver-properties",
+ short_version,
+ argc, argv, NULL, 0, NULL);
+ /* init_results is:
+ 0 upon successful initialization;
+ 1 if --init-session-settings was passed on the cmdline;
+ 2 if --ignore was passed on the cmdline;
+ -1 on error.
+
+ So the 1 signifies just to init the settings, and quit, basically.
+ (Meaning launch the xscreensaver daemon.)
+ */
+
+ if (init_results < 0)
+ {
+# if 0
+ g_error ("An initialization error occurred while "
+ "starting xscreensaver-capplet.\n");
+# else /* !0 */
+ fprintf (stderr, "%s: gnome_capplet_init failed: %d\n",
+ real_progname, init_results);
+ exit (1);
+# endif /* !0 */
+ }
+
+ client = gnome_master_client ();
+
+ if (client)
+ flags = gnome_client_get_flags (client);
+
+ if (flags & GNOME_CLIENT_IS_CONNECTED)
+ {
+ int token =
+ gnome_startup_acquire_token ("GNOME_SCREENSAVER_PROPERTIES",
+ gnome_client_get_id (client));
+ if (token)
+ {
+ char *session_args[20];
+ int i = 0;
+ session_args[i++] = real_progname;
+ session_args[i++] = "--capplet";
+ session_args[i++] = "--init-session-settings";
+ session_args[i] = 0;
+ gnome_client_set_priority (client, 20);
+ gnome_client_set_restart_style (client, GNOME_RESTART_ANYWAY);
+ gnome_client_set_restart_command (client, i, session_args);
+ }
+ else
+ {
+ gnome_client_set_restart_style (client, GNOME_RESTART_NEVER);
+ }
+
+ gnome_client_flush (client);
+ }
+
+ if (init_results == 1)
+ {
+ system ("xscreensaver -nosplash &");
+ return 0;
+ }
+
+ }
+ else
+# endif /* HAVE_CRAPPLET */
+ {
+ gtk_init (&argc, &argv);
+ }
/* We must read exactly the same resources as xscreensaver.
s++;
if (!strcmp (s, "-prefs"))
prefs = True;
+ else if (crapplet_p)
+ /* There are lots of random args that we don't care about when we're
+ started as a crapplet, so just ignore unknown args in that case. */
+ ;
else
{
- fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n",
- real_progname);
- exit (1);
+ fprintf (stderr, "%s: unknown option: %s\n", real_progname, argv[i]);
+ USAGE ();
+ exit (1);
}
}
/* Create the window and all its widgets.
*/
gtk_window = create_xscreensaver_demo ();
+ toplevel_widget = gtk_window;
/* Set the window's title. */
{
sensitize_demo_widgets (gtk_window, False);
fix_text_entry_sizes (gtk_window);
scroll_to_current_hack (gtk_window, pair);
- gtk_widget_show (gtk_window);
- /* The next three calls must come after gtk_widget_show(). */
- pixmapify_buttons (gtk_window);
- eschew_gtk_lossage (gtk_window);
- ensure_selected_item_visible (GTK_WIDGET(name_to_widget(gtk_window,"list")));
+ gtk_signal_connect (
+ GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "list")),
+ "map", GTK_SIGNAL_FUNC(map_window_cb), 0);
+ gtk_signal_connect (
+ GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "prev")),
+ "map", GTK_SIGNAL_FUNC(map_prev_button_cb), 0);
+ gtk_signal_connect (
+ GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "next")),
+ "map", GTK_SIGNAL_FUNC(map_next_button_cb), 0);
+
/* Handle the -prefs command-line argument. */
if (prefs)
gtk_notebook_set_page (notebook, 1);
}
- /* Issue any warnings about the running xscreensaver daemon. */
- the_network_is_not_the_computer (gtk_window);
+# ifdef HAVE_CRAPPLET
+ if (crapplet_p)
+ {
+ GtkWidget *capplet;
+ GtkWidget *top_vbox;
+
+ capplet = capplet_widget_new ();
+
+ top_vbox = GTK_BIN (gtk_window)->child;
+
+ gtk_widget_ref (top_vbox);
+ gtk_container_remove (GTK_CONTAINER (gtk_window), top_vbox);
+ GTK_OBJECT_SET_FLAGS (top_vbox, GTK_FLOATING);
+
+ /* In crapplet-mode, take off the menubar. */
+ gtk_widget_hide (name_to_widget (gtk_window, "menubar"));
+
+ gtk_container_add (GTK_CONTAINER (capplet), top_vbox);
+ gtk_widget_show (capplet);
+ gtk_widget_hide (gtk_window);
+
+ /* Hook up the Control Center's redundant Help button, too. */
+ gtk_signal_connect (GTK_OBJECT (capplet), "help",
+ GTK_SIGNAL_FUNC (doc_menu_cb), 0);
+
+ /* Issue any warnings about the running xscreensaver daemon. */
+ the_network_is_not_the_computer (top_vbox);
+ }
+ else
+# endif /* HAVE_CRAPPLET */
+ {
+ gtk_widget_show (gtk_window);
+
+ /* Issue any warnings about the running xscreensaver daemon. */
+ the_network_is_not_the_computer (gtk_window);
+ }
/* Run the Gtk event loop, and not the Xt event loop. This means that
if there were Xt timers or fds registered, they would never get serviced,
Xt so that we could process the command line and use the X resource
manager.
*/
- gtk_main ();
+ initializing_p = False;
+
+# ifdef HAVE_CRAPPLET
+ if (crapplet_p)
+ capplet_gtk_main ();
+ else
+# endif /* HAVE_CRAPPLET */
+ gtk_main ();
+
exit (0);
}