/* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
- * xscreensaver, Copyright (c) 1993-2002 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2007 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 <unistd.h>
#endif
+# ifdef __GNUC__
+# define STFU __extension__ /* ignore gcc -pendantic warnings in next sexp */
+# else
+# define STFU /* */
+# endif
+
+
#ifdef ENABLE_NLS
# include <locale.h>
#endif /* ENABLE_NLS */
# include "xmu.h"
#endif
+#ifdef HAVE_XINERAMA
+# include <X11/extensions/Xinerama.h>
+#endif /* HAVE_XINERAMA */
+
#include <gtk/gtk.h>
#ifdef HAVE_CRAPPLET
#include <gdk/gdkx.h>
#ifdef HAVE_GTK2
-#include <glade/glade-xml.h>
-#endif /* HAVE_GTK2 */
+# include <glade/glade-xml.h>
+# include <gmodule.h>
+#else /* !HAVE_GTK2 */
+# define G_MODULE_EXPORT /**/
+#endif /* !HAVE_GTK2 */
#if defined(DEFAULT_ICONDIR) && !defined(GLADE_DIR)
# define GLADE_DIR DEFAULT_ICONDIR
# define DEFAULT_ICONDIR GLADE_DIR
#endif
+#ifndef HAVE_XML
+ /* Kludge: this is defined in demo-Gtk-conf.c when HAVE_XML.
+ It is unused otherwise, so in that case, stub it out. */
+ static const char *hack_configuration_path = 0;
+#endif
+
+
#include "version.h"
#include "prefs.h"
#include "logo-50.xpm"
#include "logo-180.xpm"
+#undef dgettext /* else these are defined twice... */
+#undef dcgettext
+
#include "demo-Gtk-widgets.h"
#include "demo-Gtk-support.h"
#include "demo-Gtk-conf.h"
/* from exec.c */
extern void exec_command (const char *shell, const char *command, int nice);
+extern int on_path_p (const char *program);
+
+static void hack_subproc_environment (Window preview_window_id, Bool debug_p);
#undef countof
#define countof(x) (sizeof((x))/sizeof((*x)))
+/* You might think that to read an array of 32-bit quantities out of a
+ server-side property, you would pass an array of 32-bit data quantities
+ into XGetWindowProperty(). You would be wrong. You have to use an array
+ of longs, even if long is 64 bits (using 32 of each 64.)
+ */
+typedef long PROP32;
+
char *progname = 0;
char *progclass = "XScreenSaver";
XrmDatabase db;
/* The order of the items in the mode menu. */
static int mode_menu_order[] = {
- DONT_BLANK, BLANK_ONLY, ONE_HACK, RANDOM_HACKS };
+ DONT_BLANK, BLANK_ONLY, ONE_HACK, RANDOM_HACKS, RANDOM_HACKS_SAME };
typedef struct {
int *list_elt_to_hack_number; /* table for sorting the hack list */
int *hack_number_to_list_elt; /* the inverse table */
+ Bool *hacks_available_p; /* whether hacks are on $PATH */
+ int total_available; /* how many are on $PATH */
+ int list_count; /* how many items are in the list: this may be
+ less than p->screenhacks_count, if some are
+ suppressed. */
int _selected_list_element; /* don't use this: call
selected_list_element() instead */
+ int nscreens; /* How many X or Xinerama screens there are */
+
saver_preferences prefs;
} state;
static int maybe_reload_init_file (state *);
static void await_xscreensaver (state *);
+static Bool xscreensaver_running_p (state *);
+static void sensitize_menu_items (state *s, Bool force_p);
+static void force_dialog_repaint (state *s);
static void schedule_preview (state *, const char *cmd);
-static void kill_preview_subproc (state *);
+static void kill_preview_subproc (state *, Bool reset_p);
static void schedule_preview_check (state *);
+\f
+/* Prototypes of functions used by the Glade-generated code,
+ to avoid warnings.
+ */
+void exit_menu_cb (GtkMenuItem *, gpointer user_data);
+void about_menu_cb (GtkMenuItem *, gpointer user_data);
+void doc_menu_cb (GtkMenuItem *, gpointer user_data);
+void file_menu_cb (GtkMenuItem *, gpointer user_data);
+void activate_menu_cb (GtkMenuItem *, gpointer user_data);
+void lock_menu_cb (GtkMenuItem *, gpointer user_data);
+void kill_menu_cb (GtkMenuItem *, gpointer user_data);
+void restart_menu_cb (GtkWidget *, gpointer user_data);
+void run_this_cb (GtkButton *, gpointer user_data);
+void manual_cb (GtkButton *, gpointer user_data);
+void run_next_cb (GtkButton *, gpointer user_data);
+void run_prev_cb (GtkButton *, gpointer user_data);
+void pref_changed_cb (GtkWidget *, gpointer user_data);
+gboolean pref_changed_event_cb (GtkWidget *, GdkEvent *, gpointer user_data);
+void mode_menu_item_cb (GtkWidget *, gpointer user_data);
+void switch_page_cb (GtkNotebook *, GtkNotebookPage *,
+ gint page_num, gpointer user_data);
+void browse_image_dir_cb (GtkButton *, gpointer user_data);
+void browse_text_file_cb (GtkButton *, gpointer user_data);
+void browse_text_program_cb (GtkButton *, gpointer user_data);
+void settings_cb (GtkButton *, gpointer user_data);
+void settings_adv_cb (GtkButton *, gpointer user_data);
+void settings_std_cb (GtkButton *, gpointer user_data);
+void settings_switch_page_cb (GtkNotebook *, GtkNotebookPage *,
+ gint page_num, gpointer user_data);
+void settings_cancel_cb (GtkButton *, gpointer user_data);
+void settings_ok_cb (GtkButton *, gpointer user_data);
\f
/* Some random utility functions
*/
+const char *blurb (void);
+
const char *
blurb (void)
{
#ifdef HAVE_GTK2
if (!s->glade_ui)
{
- s->glade_ui = glade_xml_new (GLADE_DIR "/xscreensaver-demo.glade2",
- NULL, NULL);
+ /* First try to load the Glade file from the current directory;
+ if there isn't one there, check the installed directory.
+ */
+# define GLADE_FILE_NAME "xscreensaver-demo.glade2"
+ const char * const files[] = { GLADE_FILE_NAME,
+ GLADE_DIR "/" GLADE_FILE_NAME };
+ int i;
+ for (i = 0; i < countof (files); i++)
+ {
+ struct stat st;
+ if (!stat (files[i], &st))
+ {
+ s->glade_ui = glade_xml_new (files[i], NULL, NULL);
+ break;
+ }
+ }
if (!s->glade_ui)
{
fprintf (stderr,
- "%s: could not load glade file"
- " \"%s/xscreensaver-demo.glade2\"\n",
- blurb(), GLADE_DIR);
+ "%s: could not load \"" GLADE_FILE_NAME "\"\n"
+ "\tfrom " GLADE_DIR "/ or current directory.\n",
+ blurb());
exit (-1);
}
+# undef GLADE_FILE_NAME
+
glade_xml_signal_autoconnect (s->glade_ui);
}
#endif /* HAVE_GTK2 */
if (w) return w;
- fprintf (stderr, "%s: no widget \"%s\"\n", blurb(), name);
+ fprintf (stderr, "%s: no widget \"%s\" (wrong Glade file?)\n",
+ blurb(), name);
abort();
}
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
- return;
-
- path = gtk_tree_model_get_path (model, &iter);
+ path = gtk_tree_path_new_first ();
+ else
+ path = gtk_tree_model_get_path (model, &iter);
- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget),
- path, NULL, FALSE, 0.0, 0.0);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE);
+
+ gtk_tree_path_free (path);
+
#else /* !HAVE_GTK2 */
GtkScrolledWindow *scroller = 0;
while (parent && !parent->window)
parent = parent->parent;
- if (!GTK_WIDGET (parent)->window) /* too early to pop up transient dialogs */
+ if (!parent ||
+ !GTK_WIDGET (parent)->window) /* too early to pop up transient dialogs */
{
fprintf (stderr, "%s: too early for dialog?\n", progname);
return;
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_SET_FLAGS (ok, GTK_CAN_DEFAULT);
+ STFU GTK_WIDGET_SET_FLAGS (ok, GTK_CAN_DEFAULT);
gtk_widget_show (ok);
gtk_widget_grab_focus (ok);
if (cancel)
{
- GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT);
+ STFU GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT);
gtk_widget_show (cancel);
}
gtk_widget_show (label);
flush_dialog_changes_and_save (s);
status = xscreensaver_command (GDK_DISPLAY(), command, arg, False, &err);
+
+ /* Kludge: ignore the spurious "window unexpectedly deleted" errors... */
+ if (status < 0 && err && strstr (err, "unexpectedly deleted"))
+ status = 0;
+
if (status < 0)
{
char buf [255];
warning_dialog (s->toplevel_widget, buf, False, 100);
}
if (err) free (err);
+
+ sensitize_menu_items (s, True);
+ force_dialog_repaint (s);
}
run_hack (state *s, int list_elt, Bool report_errors_p)
{
int hack_number;
+ char *err = 0;
+ int status;
+
if (list_elt < 0) return;
hack_number = s->list_elt_to_hack_number[list_elt];
flush_dialog_changes_and_save (s);
schedule_preview (s, 0);
- if (report_errors_p)
- run_cmd (s, XA_DEMO, hack_number + 1);
- else
+
+ status = xscreensaver_command (GDK_DISPLAY(), XA_DEMO, hack_number + 1,
+ False, &err);
+
+ if (status < 0 && report_errors_p)
{
- char *s = 0;
- xscreensaver_command (GDK_DISPLAY(), XA_DEMO, hack_number + 1,
- False, &s);
- if (s) free (s);
+ if (xscreensaver_running_p (s))
+ {
+ /* Kludge: ignore the spurious "window unexpectedly deleted"
+ errors... */
+ if (err && strstr (err, "unexpectedly deleted"))
+ status = 0;
+
+ if (status < 0)
+ {
+ char buf [255];
+ if (err)
+ sprintf (buf, "Error:\n\n%s", err);
+ else
+ strcpy (buf, "Unknown error!");
+ warning_dialog (s->toplevel_widget, buf, False, 100);
+ }
+ }
+ else
+ {
+ /* The error is that the daemon isn't running;
+ offer to restart it.
+ */
+ const char *d = DisplayString (GDK_DISPLAY());
+ char msg [1024];
+ sprintf (msg,
+ _("Warning:\n\n"
+ "The XScreenSaver daemon doesn't seem to be running\n"
+ "on display \"%s\". Launch it now?"),
+ d);
+ warning_dialog (s->toplevel_widget, msg, True, 1);
+ }
}
+
+ if (err) free (err);
+
+ sensitize_menu_items (s, False);
}
\f
/* Button callbacks
+
+ According to Eric Lassauge, this G_MODULE_EXPORT crud is needed to make
+ libglade work on Cygwin; apparently all Glade callbacks need this magic
+ extra declaration. I do not pretend to understand.
*/
-void
+G_MODULE_EXPORT void
exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
flush_dialog_changes_and_save (s);
- kill_preview_subproc (s);
+ kill_preview_subproc (s, False);
gtk_main_quit ();
}
-static void
+static gboolean
wm_toplevel_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
{
state *s = (state *) data;
flush_dialog_changes_and_save (s);
gtk_main_quit ();
+ return TRUE;
}
-void
+G_MODULE_EXPORT void
about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
char msg [2048];
*s = 0;
s += 2;
+ /* Ole Laursen <olau@hardworking.dk> says "don't use _() here because
+ non-ASCII characters aren't allowed in localizable string keys."
+ (I don't want to just use (c) instead of © because that doesn't
+ look as good in the plain-old default Latin1 "C" locale.)
+ */
#ifdef HAVE_GTK2
- sprintf(copy, _("Copyright \xC2\xA9 1991-2002 %s"), s);
+ sprintf(copy, ("Copyright \xC2\xA9 1991-2006 %s"), s);
#else /* !HAVE_GTK2 */
- sprintf(copy, _("Copyright \251 1991-2002 %s"), s);
+ sprintf(copy, ("Copyright \251 1991-2006 %s"), s);
#endif /* !HAVE_GTK2 */
sprintf (msg, "%s\n\n%s", copy, desc);
}
-void
+G_MODULE_EXPORT void
doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
}
help_command = (char *) malloc (strlen (p->load_url_command) +
- (strlen (p->help_url) * 2) + 20);
+ (strlen (p->help_url) * 4) + 20);
strcpy (help_command, "( ");
sprintf (help_command + strlen(help_command),
- p->load_url_command, p->help_url, p->help_url);
+ p->load_url_command,
+ p->help_url, p->help_url, p->help_url, p->help_url);
strcat (help_command, " ) &");
- system (help_command);
+ if (system (help_command) < 0)
+ fprintf (stderr, "%s: fork error\n", blurb());
free (help_command);
}
-void
+G_MODULE_EXPORT void
+file_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
+{
+ state *s = global_state_kludge; /* I hate C so much... */
+ sensitize_menu_items (s, False);
+}
+
+
+G_MODULE_EXPORT void
activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
}
-void
+G_MODULE_EXPORT void
lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
}
-void
+G_MODULE_EXPORT void
kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
}
-void
+G_MODULE_EXPORT void
restart_menu_cb (GtkWidget *widget, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
flush_dialog_changes_and_save (s);
xscreensaver_command (GDK_DISPLAY(), XA_EXIT, 0, False, NULL);
sleep (1);
- system ("xscreensaver -nosplash &");
+ if (system ("xscreensaver -nosplash &") < 0)
+ fprintf (stderr, "%s: fork error\n", blurb());
await_xscreensaver (s);
}
+static Bool
+xscreensaver_running_p (state *s)
+{
+ Display *dpy = GDK_DISPLAY();
+ char *rversion = 0;
+ server_xscreensaver_version (dpy, &rversion, 0, 0);
+ if (!rversion)
+ return False;
+ free (rversion);
+ return True;
+}
+
static void
await_xscreensaver (state *s)
{
int countdown = 5;
+ Bool ok = False;
- Display *dpy = GDK_DISPLAY();
- /* GtkWidget *dialog = 0;*/
- char *rversion = 0;
+ while (!ok && (--countdown > 0))
+ if (xscreensaver_running_p (s))
+ ok = True;
+ else
+ sleep (1); /* If it's not there yet, wait a second... */
- 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... */
- if (!rversion)
- sleep (1);
- }
+ sensitize_menu_items (s, True);
-/* if (dialog) gtk_widget_destroy (dialog);*/
-
- if (rversion)
- {
- /* Got it. */
- free (rversion);
- }
- else
+ if (! ok)
{
/* Timed out, no screensaver running. */
"\n"));
if (root_p)
+
+# ifdef __GNUC__
+ __extension__ /* don't warn about "string length is greater than
+ the length ISO C89 compilers are required to
+ support" in the following expression... */
+# endif
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"
warning_dialog (s->toplevel_widget, buf, False, 1);
}
+
+ force_dialog_repaint (s);
}
static int
demo_write_init_file (state *s, saver_preferences *p)
{
+ Display *dpy = GDK_DISPLAY();
#if 0
/* #### try to figure out why shit keeps getting reordered... */
abort();
#endif
- if (!write_init_file (p, s->short_version, False))
+ if (!write_init_file (dpy, p, s->short_version, False))
{
if (s->debug_p)
fprintf (stderr, "%s: wrote %s\n", blurb(), init_file_name());
}
-void
+G_MODULE_EXPORT void
run_this_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
}
-void
+G_MODULE_EXPORT void
manual_cb (GtkButton *button, gpointer user_data)
{
+ Display *dpy = GDK_DISPLAY();
state *s = global_state_kludge; /* I hate C so much... */
saver_preferences *p = &s->prefs;
- GtkList *list_widget = GTK_LIST (name_to_widget (s, "list"));
+ GtkWidget *list_widget = name_to_widget (s, "list");
int list_elt = selected_list_element (s);
int hack_number;
char *name, *name2, *cmd, *str;
+ char *oname = 0;
if (list_elt < 0) return;
hack_number = s->list_elt_to_hack_number[list_elt];
flush_dialog_changes_and_save (s);
- ensure_selected_item_visible (GTK_WIDGET (list_widget));
+ ensure_selected_item_visible (list_widget);
name = strdup (p->screenhacks[hack_number]->command);
name2 = name;
+ oname = name;
while (isspace (*name2)) name2++;
str = name2;
while (*str && !isspace (*str)) str++;
*str = 0;
str = strrchr (name2, '/');
- if (str) name = str+1;
+ if (str) name2 = str+1;
- cmd = get_string_resource ("manualCommand", "ManualCommand");
+ cmd = get_string_resource (dpy, "manualCommand", "ManualCommand");
if (cmd)
{
- char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
+ char *cmd2 = (char *) malloc (strlen (cmd) + (strlen (name2) * 4) + 100);
strcpy (cmd2, "( ");
sprintf (cmd2 + strlen (cmd2),
cmd,
name2, name2, name2, name2);
strcat (cmd2, " ) &");
- system (cmd2);
+ if (system (cmd2) < 0)
+ fprintf (stderr, "%s: fork error\n", blurb());
free (cmd2);
}
else
False, 100);
}
- free (name);
+ free (oname);
}
if (!was) gtk_widget_set_sensitive (parent, True);
#ifdef HAVE_GTK2
model = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
- g_assert (model);
- gtk_tree_model_iter_nth_child (model, &iter, NULL, list_elt);
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
- gtk_tree_selection_select_iter (selection, &iter);
+ STFU g_assert (model);
+ if (gtk_tree_model_iter_nth_child (model, &iter, NULL, list_elt))
+ {
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
#else /* !HAVE_GTK2 */
gtk_list_select_item (GTK_LIST (list), list_elt);
#endif /* !HAVE_GTK2 */
}
-void
+G_MODULE_EXPORT void
run_next_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
- saver_preferences *p = &s->prefs;
+ /* saver_preferences *p = &s->prefs; */
Bool ops = s->preview_suppressed_p;
GtkWidget *list_widget = name_to_widget (s, "list");
else
list_elt++;
- if (list_elt >= p->screenhacks_count)
+ if (list_elt >= s->list_count)
list_elt = 0;
s->preview_suppressed_p = True;
}
-void
+G_MODULE_EXPORT void
run_prev_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
- saver_preferences *p = &s->prefs;
+ /* saver_preferences *p = &s->prefs; */
Bool ops = s->preview_suppressed_p;
GtkWidget *list_widget = name_to_widget (s, "list");
int list_elt = selected_list_element (s);
if (list_elt < 0)
- list_elt = p->screenhacks_count - 1;
+ list_elt = s->list_count - 1;
else
list_elt--;
if (list_elt < 0)
- list_elt = p->screenhacks_count - 1;
+ list_elt = s->list_count - 1;
s->preview_suppressed_p = True;
Bool changed = False;
screenhack *hack;
int hack_number;
- if (list_elt < 0 || list_elt >= p->screenhacks_count)
+ if (list_elt < 0 || list_elt >= s->list_count)
abort();
hack_number = s->list_elt_to_hack_number[list_elt];
else
{
char c;
- if (sscanf (line, "%u%c", &value, &c) != 1)
+ if (sscanf (line, "%d%c", &value, &c) != 1)
value = -1;
if (!sec_p)
value *= 60;
return True;
}
+static Bool
+file_p (const char *path)
+{
+ struct stat st;
+ if (!path || !*path)
+ return False;
+ else if (stat (path, &st))
+ return False;
+ else if (S_ISDIR (st.st_mode))
+ return False;
+ else
+ return True;
+}
+
static char *
normalize_directory (const char *path)
{
int L;
char *p2, *s;
- if (!path) return 0;
- L = strlen (path);;
+ if (!path || !*path) return 0;
+ L = strlen (path);
p2 = (char *) malloc (L + 2);
strcpy (p2, path);
if (p2[L-1] == '/') /* remove trailing slash */
w = name_to_widget (s, (NAME)); \
(FIELD) = normalize_directory (gtk_entry_get_text (GTK_ENTRY (w)))
+# define TEXT(FIELD,NAME) \
+ w = name_to_widget (s, (NAME)); \
+ (FIELD) = (char *) gtk_entry_get_text (GTK_ENTRY (w))
+
MINUTES (&p2->timeout, "timeout_spinbutton");
MINUTES (&p2->cycle, "cycle_spinbutton");
CHECKBOX (p2->lock_p, "lock_button");
CHECKBOX (p2->random_image_p, "grab_image_button");
PATHNAME (p2->image_directory, "image_text");
+#if 0
CHECKBOX (p2->verbose_p, "verbose_button");
CHECKBOX (p2->capture_stderr_p, "capture_button");
CHECKBOX (p2->splash_p, "splash_button");
+#endif
+
+ {
+ Bool v = False;
+ CHECKBOX (v, "text_host_radio"); if (v) p2->tmode = TEXT_DATE;
+ CHECKBOX (v, "text_radio"); if (v) p2->tmode = TEXT_LITERAL;
+ CHECKBOX (v, "text_file_radio"); if (v) p2->tmode = TEXT_FILE;
+ CHECKBOX (v, "text_program_radio"); if (v) p2->tmode = TEXT_PROGRAM;
+ CHECKBOX (v, "text_url_radio"); if (v) p2->tmode = TEXT_URL;
+ TEXT (p2->text_literal, "text_entry");
+ PATHNAME (p2->text_file, "text_file_entry");
+ PATHNAME (p2->text_program, "text_program_entry");
+ PATHNAME (p2->text_program, "text_program_entry");
+ TEXT (p2->text_url, "text_url_entry");
+ }
CHECKBOX (p2->install_cmap_p, "install_button");
CHECKBOX (p2->fade_p, "fade_button");
# undef MINUTES
# undef CHECKBOX
# undef PATHNAME
+# undef TEXT
/* Warn if the image directory doesn't exist.
*/
if (p->field != p2->field) { \
changed = True; \
if (s->debug_p) \
- fprintf (stderr, "%s: %s => %d\n", blurb(), name, p2->field); \
+ fprintf (stderr, "%s: %s => %d\n", blurb(), name, (int) p2->field); \
} \
p->field = p2->field
COPY(dpms_suspend, "dpms_suspend");
COPY(dpms_off, "dpms_off");
+#if 0
COPY(verbose_p, "verbose_p");
COPY(capture_stderr_p, "capture_stderr_p");
COPY(splash_p, "splash_p");
+#endif
+
+ COPY(tmode, "tmode");
COPY(install_cmap_p, "install_cmap_p");
COPY(fade_p, "fade_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;
+# define COPYSTR(FIELD,NAME) \
+ if (!p->FIELD || \
+ !p2->FIELD || \
+ strcmp(p->FIELD, p2->FIELD)) \
+ { \
+ changed = True; \
+ if (s->debug_p) \
+ fprintf (stderr, "%s: %s => \"%s\"\n", blurb(), NAME, p2->FIELD); \
+ } \
+ if (p->FIELD && p->FIELD != p2->FIELD) \
+ free (p->FIELD); \
+ p->FIELD = p2->FIELD; \
+ p2->FIELD = 0
+
+ COPYSTR(image_directory, "image_directory");
+ COPYSTR(text_literal, "text_literal");
+ COPYSTR(text_file, "text_file");
+ COPYSTR(text_program, "text_program");
+ COPYSTR(text_url, "text_url");
+# undef COPYSTR
populate_prefs_page (s);
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, " %lu %c", &id, &c)) ;
else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
else
{
}
-void
+G_MODULE_EXPORT void
pref_changed_cb (GtkWidget *widget, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
}
}
-gboolean
+G_MODULE_EXPORT gboolean
pref_changed_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
pref_changed_cb (widget, user_data);
/* Callback on menu items in the "mode" options menu.
*/
-void
+G_MODULE_EXPORT void
mode_menu_item_cb (GtkWidget *widget, gpointer user_data)
{
state *s = (state *) user_data;
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)
{
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".
+ switching *to* "one screensaver" mode from any other mode, set
+ "the one" to be that which is currently selected.
*/
- list_elt = -1;
+ list_elt = selected_list_element (s);
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);
+ p->selected_hack = s->list_elt_to_hack_number[list_elt];
{
saver_mode old_mode = p->mode;
}
pref_changed_cb (widget, user_data);
-
- if (old_selected != p->selected_hack)
- abort(); /* dammit, not again... */
}
-void
+G_MODULE_EXPORT void
switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page,
gint page_num, gpointer user_data)
{
char *str;
int list_elt;
- g_return_if_fail (!gdk_pointer_is_grabbed ());
+ STFU g_return_if_fail (!gdk_pointer_is_grabbed ());
str = gtk_tree_path_to_string (path);
list_elt = strtol (str, NULL, 10);
populate_demo_window (s, list_elt);
flush_dialog_changes_and_save (s);
+
+ /* Re-populate the Settings window any time a new item is selected
+ in the list, in case both windows are currently visible.
+ */
+ populate_popup_window (s);
}
#else /* !HAVE_GTK2 */
}
+static void
+store_text_file (GtkWidget *button, gpointer user_data)
+{
+ file_selection_data *fsd = (file_selection_data *) user_data;
+ state *s = fsd->state;
+ GtkFileSelection *selector = fsd->widget;
+ GtkWidget *top = s->toplevel_widget;
+ saver_preferences *p = &s->prefs;
+ const char *path = gtk_file_selection_get_filename (selector);
+
+ if (p->text_file && !strcmp(p->text_file, path))
+ return; /* no change */
+
+ if (!file_p (path))
+ {
+ char b[255];
+ sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path);
+ warning_dialog (GTK_WIDGET (top), b, False, 100);
+ return;
+ }
+
+ if (p->text_file) free (p->text_file);
+ p->text_file = normalize_directory (path);
+
+ gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_file_entry")),
+ (p->text_file ? p->text_file : ""));
+ demo_write_init_file (s, p);
+}
+
+
+static void
+store_text_program (GtkWidget *button, gpointer user_data)
+{
+ file_selection_data *fsd = (file_selection_data *) user_data;
+ state *s = fsd->state;
+ GtkFileSelection *selector = fsd->widget;
+ /*GtkWidget *top = s->toplevel_widget;*/
+ saver_preferences *p = &s->prefs;
+ const char *path = gtk_file_selection_get_filename (selector);
+
+ if (p->text_program && !strcmp(p->text_program, path))
+ return; /* no change */
+
+# if 0
+ if (!file_p (path))
+ {
+ char b[255];
+ sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path);
+ warning_dialog (GTK_WIDGET (top), b, False, 100);
+ return;
+ }
+# endif
+
+ if (p->text_program) free (p->text_program);
+ p->text_program = normalize_directory (path);
+
+ gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_program_entry")),
+ (p->text_program ? p->text_program : ""));
+ demo_write_init_file (s, p);
+}
+
+
+
static void
browse_image_dir_cancel (GtkWidget *button, gpointer user_data)
{
store_image_directory (button, user_data);
}
+static void
+browse_text_file_ok (GtkWidget *button, gpointer user_data)
+{
+ browse_image_dir_cancel (button, user_data);
+ store_text_file (button, user_data);
+}
+
+static void
+browse_text_program_ok (GtkWidget *button, gpointer user_data)
+{
+ browse_image_dir_cancel (button, user_data);
+ store_text_program (button, user_data);
+}
+
static void
browse_image_dir_close (GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
}
-void
+G_MODULE_EXPORT void
browse_image_dir_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
}
-void
+G_MODULE_EXPORT void
+browse_text_file_cb (GtkButton *button, gpointer user_data)
+{
+ state *s = global_state_kludge; /* I hate C so much... */
+ saver_preferences *p = &s->prefs;
+ static file_selection_data *fsd = 0;
+
+ GtkFileSelection *selector = GTK_FILE_SELECTION(
+ gtk_file_selection_new ("Please select a text file."));
+
+ if (!fsd)
+ fsd = (file_selection_data *) malloc (sizeof (*fsd));
+
+ fsd->widget = selector;
+ fsd->state = s;
+
+ if (p->text_file && *p->text_file)
+ gtk_file_selection_set_filename (selector, p->text_file);
+
+ gtk_signal_connect (GTK_OBJECT (selector->ok_button),
+ "clicked", GTK_SIGNAL_FUNC (browse_text_file_ok),
+ (gpointer *) fsd);
+ gtk_signal_connect (GTK_OBJECT (selector->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC (browse_image_dir_cancel),
+ (gpointer *) fsd);
+ gtk_signal_connect (GTK_OBJECT (selector), "delete_event",
+ GTK_SIGNAL_FUNC (browse_image_dir_close),
+ (gpointer *) fsd);
+
+ gtk_window_set_modal (GTK_WINDOW (selector), True);
+ gtk_widget_show (GTK_WIDGET (selector));
+}
+
+
+G_MODULE_EXPORT void
+browse_text_program_cb (GtkButton *button, gpointer user_data)
+{
+ state *s = global_state_kludge; /* I hate C so much... */
+ saver_preferences *p = &s->prefs;
+ static file_selection_data *fsd = 0;
+
+ GtkFileSelection *selector = GTK_FILE_SELECTION(
+ gtk_file_selection_new ("Please select a text-generating program."));
+
+ if (!fsd)
+ fsd = (file_selection_data *) malloc (sizeof (*fsd));
+
+ fsd->widget = selector;
+ fsd->state = s;
+
+ if (p->text_program && *p->text_program)
+ gtk_file_selection_set_filename (selector, p->text_program);
+
+ gtk_signal_connect (GTK_OBJECT (selector->ok_button),
+ "clicked", GTK_SIGNAL_FUNC (browse_text_program_ok),
+ (gpointer *) fsd);
+ gtk_signal_connect (GTK_OBJECT (selector->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC (browse_image_dir_cancel),
+ (gpointer *) fsd);
+ gtk_signal_connect (GTK_OBJECT (selector), "delete_event",
+ GTK_SIGNAL_FUNC (browse_image_dir_close),
+ (gpointer *) fsd);
+
+ gtk_window_set_modal (GTK_WINDOW (selector), True);
+ gtk_widget_show (GTK_WIDGET (selector));
+}
+
+
+
+
+
+G_MODULE_EXPORT void
settings_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
# endif /* HAVE_XML */
}
-void
+G_MODULE_EXPORT void
settings_adv_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
gtk_notebook_set_page (notebook, 1);
}
-void
+G_MODULE_EXPORT void
settings_std_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
gtk_notebook_set_page (notebook, 0);
}
-void
+G_MODULE_EXPORT void
settings_switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page,
gint page_num, gpointer user_data)
{
-void
+G_MODULE_EXPORT void
settings_cancel_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
gtk_widget_hide (s->popup_widget);
}
-void
+G_MODULE_EXPORT void
settings_ok_cb (GtkButton *button, gpointer user_data)
{
state *s = global_state_kludge; /* I hate C so much... */
gtk_widget_hide (s->popup_widget);
}
-static void
+static gboolean
wm_popup_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
{
state *s = (state *) data;
settings_cancel_cb (0, (gpointer) s);
+ return TRUE;
}
Atom type;
int format;
unsigned long nitems, bytesafter;
- CARD32 *data = 0;
+ unsigned char *dataP = 0;
Display *dpy = GDK_DISPLAY();
int hack_number = -1;
XA_SCREENSAVER_STATUS,
0, 3, False, XA_INTEGER,
&type, &format, &nitems, &bytesafter,
- (unsigned char **) &data)
+ &dataP)
== Success
&& type == XA_INTEGER
&& nitems >= 3
- && data)
- hack_number = (int) data[2] - 1;
+ && dataP)
+ {
+ PROP32 *data = (PROP32 *) dataP;
+ hack_number = (int) data[2] - 1;
+ }
- if (data) free (data);
+ if (dataP) XFree (dataP);
return hack_number;
}
-/* Finds the number of the last hack to run, and makes that item be
+/* Finds the number of the last hack that was run, and makes that item be
selected by default.
*/
static void
scroll_to_current_hack (state *s)
{
saver_preferences *p = &s->prefs;
- int hack_number;
+ int hack_number = -1;
- if (p->mode == ONE_HACK)
+ if (p->mode == ONE_HACK) /* in "one" mode, use the one */
hack_number = p->selected_hack;
- else
+ if (hack_number < 0) /* otherwise, use the last-run */
hack_number = server_current_hack ();
+ if (hack_number < 0) /* failing that, last "one mode" */
+ hack_number = p->selected_hack;
+ if (hack_number < 0) /* failing that, newest hack. */
+ {
+ /* We should only get here if the user does not have a .xscreensaver
+ file, and the screen has not been blanked with a hack since X
+ started up: in other words, this is probably a fresh install.
+
+ Instead of just defaulting to hack #0 (in either "programs" or
+ "alphabetical" order) let's try to default to the last runnable
+ hack in the "programs" list: this is probably the hack that was
+ most recently added to the xscreensaver distribution (and so
+ it's probably the currently-coolest one!)
+ */
+ hack_number = p->screenhacks_count-1;
+ while (hack_number > 0 &&
+ ! (s->hacks_available_p[hack_number] &&
+ p->screenhacks[hack_number]->enabled_p))
+ hack_number--;
+ }
if (hack_number >= 0 && hack_number < p->screenhacks_count)
{
static void
populate_hack_list (state *s)
{
+ Display *dpy = GDK_DISPLAY();
#ifdef HAVE_GTK2
saver_preferences *p = &s->prefs;
GtkTreeView *list = GTK_TREE_VIEW (name_to_widget (s, "list"));
ren = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (list, COL_NAME,
_("Screen Saver"), ren,
- "text", COL_NAME,
+ "markup", COL_NAME,
NULL);
g_signal_connect_after (list, "row_activated",
}
- for (i = 0; i < p->screenhacks_count; i++)
+ for (i = 0; i < s->list_count; i++)
{
- screenhack *hack = p->screenhacks[s->list_elt_to_hack_number[i]];
+ int hack_number = s->list_elt_to_hack_number[i];
+ screenhack *hack = (hack_number < 0 ? 0 : p->screenhacks[hack_number]);
+ char *pretty_name;
+ Bool available_p = (hack && s->hacks_available_p [hack_number]);
- char *pretty_name = (hack->name
- ? strdup (hack->name)
- : make_hack_name (hack->command));
+ if (!hack) continue;
+
+ /* If we're to suppress uninstalled hacks, check $PATH now. */
+ if (p->ignore_uninstalled_p && !available_p)
+ continue;
+
+ pretty_name = (hack->name
+ ? strdup (hack->name)
+ : make_hack_name (dpy, hack->command));
+
+ if (!available_p)
+ {
+ /* Make the text foreground be the color of insensitive widgets
+ (but don't actually make it be insensitive, since we still
+ want to be able to click on it.)
+ */
+ GtkStyle *style = GTK_WIDGET (list)->style;
+ GdkColor *fg = &style->fg[GTK_STATE_INSENSITIVE];
+ /* GdkColor *bg = &style->bg[GTK_STATE_INSENSITIVE]; */
+ char *buf = (char *) malloc (strlen (pretty_name) + 100);
+
+ sprintf (buf, "<span foreground=\"#%02X%02X%02X\""
+ /* " background=\"#%02X%02X%02X\"" */
+ ">%s</span>",
+ fg->red >> 8, fg->green >> 8, fg->blue >> 8,
+ /* bg->red >> 8, bg->green >> 8, bg->blue >> 8, */
+ pretty_name);
+ free (pretty_name);
+ pretty_name = buf;
+ }
gtk_list_store_append (model, &iter);
gtk_list_store_set (model, &iter,
COL_ENABLED, hack->enabled_p,
COL_NAME, pretty_name,
-1);
-
free (pretty_name);
}
saver_preferences *p = &s->prefs;
GtkList *list = GTK_LIST (name_to_widget (s, "list"));
int i;
- for (i = 0; i < p->screenhacks_count; i++)
+ for (i = 0; i < s->list_count; i++)
{
- screenhack *hack = p->screenhacks[s->list_elt_to_hack_number[i]];
+ int hack_number = s->list_elt_to_hack_number[i];
+ screenhack *hack = (hack_number < 0 ? 0 : p->screenhacks[hack_number]);
/* A GtkList must contain only GtkListItems, but those can contain
an arbitrary widget. We add an Hbox, and inside that, a Checkbox
GtkWidget *line_hbox;
GtkWidget *line_check;
GtkWidget *line_label;
+ char *pretty_name;
+ Bool available_p = (hack && s->hacks_available_p [hack_number]);
- char *pretty_name = (hack->name
- ? strdup (hack->name)
- : make_hack_name (hack->command));
+ if (!hack) continue;
+
+ /* If we're to suppress uninstalled hacks, check $PATH now. */
+ if (p->ignore_uninstalled_p && !available_p)
+ continue;
+
+ pretty_name = (hack->name
+ ? strdup (hack->name)
+ : make_hack_name (hack->command));
line = gtk_list_item_new ();
line_hbox = gtk_hbox_new (FALSE, 0);
GTK_SIGNAL_FUNC (list_checkbox_cb),
(gpointer) s);
-#if 0 /* #### */
- GTK_WIDGET (GTK_BIN(line)->child)->style =
- gtk_style_copy (GTK_WIDGET (text_line)->style);
-#endif
gtk_widget_show (line);
+
+ if (!available_p)
+ {
+ /* Make the widget be colored like insensitive widgets
+ (but don't actually make it be insensitive, since we
+ still want to be able to click on it.)
+ */
+ GtkRcStyle *rc_style;
+ GdkColor fg, bg;
+
+ gtk_widget_realize (GTK_WIDGET (line_label));
+
+ fg = GTK_WIDGET (line_label)->style->fg[GTK_STATE_INSENSITIVE];
+ bg = GTK_WIDGET (line_label)->style->bg[GTK_STATE_INSENSITIVE];
+
+ rc_style = gtk_rc_style_new ();
+ rc_style->fg[GTK_STATE_NORMAL] = fg;
+ rc_style->bg[GTK_STATE_NORMAL] = bg;
+ rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_FG|GTK_RC_BG;
+
+ gtk_widget_modify_style (GTK_WIDGET (line_label), rc_style);
+ gtk_rc_style_unref (rc_style);
+ }
}
gtk_signal_connect (GTK_OBJECT (list), "select_child",
update_list_sensitivity (state *s)
{
saver_preferences *p = &s->prefs;
- Bool sensitive = (p->mode == RANDOM_HACKS || p->mode == ONE_HACK);
- Bool checkable = (p->mode == RANDOM_HACKS);
+ Bool sensitive = (p->mode == RANDOM_HACKS ||
+ p->mode == RANDOM_HACKS_SAME ||
+ p->mode == ONE_HACK);
+ Bool checkable = (p->mode == RANDOM_HACKS ||
+ p->mode == RANDOM_HACKS_SAME);
Bool blankable = (p->mode != DONT_BLANK);
#ifndef HAVE_GTK2
{
saver_preferences *p = &s->prefs;
+ Bool can_lock_p = True;
+
+ /* Disable all the "lock" controls if locking support was not provided
+ at compile-time, or if running on MacOS. */
+# if defined(NO_LOCKING) || defined(__APPLE__)
+ can_lock_p = False;
+# endif
+
+
+ /* If there is only one screen, the mode menu contains
+ "random" but not "random-same".
+ */
+ if (s->nscreens <= 1 && p->mode == RANDOM_HACKS_SAME)
+ p->mode = RANDOM_HACKS;
+
+
/* The file supports timeouts of less than a minute, but the GUI does
not, so throttle the values to be at least one minute (since "0" is
a bad rounding choice...)
# define THROTTLE(NAME) if (p->NAME != 0 && p->NAME < 60000) p->NAME = 60000
THROTTLE (timeout);
THROTTLE (cycle);
- THROTTLE (passwd_timeout);
+ /* THROTTLE (passwd_timeout); */ /* GUI doesn't set this; leave it alone */
# undef THROTTLE
# define FMT_MINUTES(NAME,N) \
(ACTIVEP))
TOGGLE_ACTIVE ("lock_button", p->lock_p);
+#if 0
TOGGLE_ACTIVE ("verbose_button", p->verbose_p);
TOGGLE_ACTIVE ("capture_button", p->capture_stderr_p);
TOGGLE_ACTIVE ("splash_button", p->splash_p);
+#endif
TOGGLE_ACTIVE ("dpms_button", p->dpms_enabled_p);
TOGGLE_ACTIVE ("grab_desk_button", p->grab_desktop_p);
TOGGLE_ACTIVE ("grab_video_button", p->grab_video_p);
TOGGLE_ACTIVE ("fade_button", p->fade_p);
TOGGLE_ACTIVE ("unfade_button", p->unfade_p);
+ switch (p->tmode)
+ {
+ case TEXT_LITERAL: TOGGLE_ACTIVE ("text_radio", True); break;
+ case TEXT_FILE: TOGGLE_ACTIVE ("text_file_radio", True); break;
+ case TEXT_PROGRAM: TOGGLE_ACTIVE ("text_program_radio", True); break;
+ case TEXT_URL: TOGGLE_ACTIVE ("text_url_radio", True); break;
+ default: TOGGLE_ACTIVE ("text_host_radio", True); break;
+ }
+
# undef TOGGLE_ACTIVE
gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "image_text")),
gtk_widget_set_sensitive (name_to_widget (s, "image_browse_button"),
p->random_image_p);
+ gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_entry")),
+ (p->text_literal ? p->text_literal : ""));
+ gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_file_entry")),
+ (p->text_file ? p->text_file : ""));
+ gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_program_entry")),
+ (p->text_program ? p->text_program : ""));
+ gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_url_entry")),
+ (p->text_url ? p->text_url : ""));
+
+ gtk_widget_set_sensitive (name_to_widget (s, "text_entry"),
+ p->tmode == TEXT_LITERAL);
+ gtk_widget_set_sensitive (name_to_widget (s, "text_file_entry"),
+ p->tmode == TEXT_FILE);
+ gtk_widget_set_sensitive (name_to_widget (s, "text_file_browse"),
+ p->tmode == TEXT_FILE);
+ gtk_widget_set_sensitive (name_to_widget (s, "text_program_entry"),
+ p->tmode == TEXT_PROGRAM);
+ gtk_widget_set_sensitive (name_to_widget (s, "text_program_browse"),
+ p->tmode == TEXT_PROGRAM);
+ gtk_widget_set_sensitive (name_to_widget (s, "text_url_entry"),
+ p->tmode == TEXT_URL);
+
+
/* Map the `saver_mode' enum to mode menu to values. */
{
GtkOptionMenu *opt = GTK_OPTION_MENU (name_to_widget (s, "mode_menu"));
{
Bool found_any_writable_cells = False;
+ Bool fading_possible = False;
Bool dpms_supported = False;
Display *dpy = GDK_DISPLAY();
- int nscreens = ScreenCount(dpy);
+ int nscreens = ScreenCount(dpy); /* real screens, not Xinerama */
int i;
for (i = 0; i < nscreens; i++)
{
}
}
+ fading_possible = found_any_writable_cells;
#ifdef HAVE_XF86VMODE_GAMMA
- found_any_writable_cells = True; /* if we can gamma fade, go for it */
+ fading_possible = True;
#endif
#ifdef HAVE_DPMS_EXTENSION
/* Blanking and Locking
*/
- SENSITIZE ("lock_spinbutton", p->lock_p);
- SENSITIZE ("lock_mlabel", p->lock_p);
+ SENSITIZE ("lock_button", can_lock_p);
+ SENSITIZE ("lock_spinbutton", can_lock_p && p->lock_p);
+ SENSITIZE ("lock_mlabel", can_lock_p && p->lock_p);
/* DPMS
*/
/* Colormaps
*/
- SENSITIZE ("cmap_frame", found_any_writable_cells);
+ SENSITIZE ("cmap_frame", found_any_writable_cells || fading_possible);
SENSITIZE ("install_button", found_any_writable_cells);
- SENSITIZE ("fade_button", found_any_writable_cells);
- SENSITIZE ("unfade_button", found_any_writable_cells);
+ SENSITIZE ("fade_button", fading_possible);
+ SENSITIZE ("unfade_button", fading_possible);
- SENSITIZE ("fade_label", (found_any_writable_cells &&
+ SENSITIZE ("fade_label", (fading_possible &&
(p->fade_p || p->unfade_p)));
- SENSITIZE ("fade_spinbutton", (found_any_writable_cells &&
+ SENSITIZE ("fade_spinbutton", (fading_possible &&
(p->fade_p || p->unfade_p)));
# undef SENSITIZE
static void
populate_popup_window (state *s)
{
- saver_preferences *p = &s->prefs;
- GtkWidget *parent = name_to_widget (s, "settings_vbox");
GtkLabel *doc = GTK_LABEL (name_to_widget (s, "doc"));
- int list_elt = selected_list_element (s);
- int hack_number = (list_elt >= 0 && list_elt < p->screenhacks_count
- ? s->list_elt_to_hack_number[list_elt]
- : -1);
- screenhack *hack = (hack_number >= 0 ? p->screenhacks[hack_number] : 0);
char *doc_string = 0;
/* #### not in Gtk 1.2
s->cdata = 0;
}
- if (hack)
- {
- GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text"));
- const char *cmd_line = gtk_entry_get_text (GTK_ENTRY (cmd));
- s->cdata = load_configurator (cmd_line, s->debug_p);
- if (s->cdata && s->cdata->widget)
- gtk_box_pack_start (GTK_BOX (parent), s->cdata->widget, TRUE, TRUE, 0);
- }
+ {
+ saver_preferences *p = &s->prefs;
+ int list_elt = selected_list_element (s);
+ int hack_number = (list_elt >= 0 && list_elt < s->list_count
+ ? s->list_elt_to_hack_number[list_elt]
+ : -1);
+ screenhack *hack = (hack_number >= 0 ? p->screenhacks[hack_number] : 0);
+ if (hack)
+ {
+ GtkWidget *parent = name_to_widget (s, "settings_vbox");
+ GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text"));
+ const char *cmd_line = gtk_entry_get_text (GTK_ENTRY (cmd));
+ s->cdata = load_configurator (cmd_line, s->debug_p);
+ if (s->cdata && s->cdata->widget)
+ gtk_box_pack_start (GTK_BOX (parent), s->cdata->widget,
+ TRUE, TRUE, 0);
+ }
+ }
doc_string = (s->cdata
? s->cdata->description
static void
sensitize_demo_widgets (state *s, Bool sensitive_p)
{
- const char *names1[] = { "demo", "settings" };
- const char *names2[] = { "cmd_label", "cmd_text", "manual",
- "visual", "visual_combo" };
+ const char *names[] = { "demo", "settings",
+ "cmd_label", "cmd_text", "manual",
+ "visual", "visual_combo" };
int i;
- for (i = 0; i < countof(names1); i++)
+ for (i = 0; i < countof(names); i++)
{
- GtkWidget *w = name_to_widget (s, names1[i]);
+ GtkWidget *w = name_to_widget (s, names[i]);
gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
}
- for (i = 0; i < countof(names2); i++)
+}
+
+
+static void
+sensitize_menu_items (state *s, Bool force_p)
+{
+ static Bool running_p = False;
+ static time_t last_checked = 0;
+ time_t now = time ((time_t *) 0);
+ const char *names[] = { "activate_menu", "lock_menu", "kill_menu",
+ /* "demo" */ };
+ int i;
+
+ if (force_p || now > last_checked + 10) /* check every 10 seconds */
+ {
+ running_p = xscreensaver_running_p (s);
+ last_checked = time ((time_t *) 0);
+ }
+
+ for (i = 0; i < countof(names); i++)
{
- GtkWidget *w = name_to_widget (s, names2[i]);
- gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
+ GtkWidget *w = name_to_widget (s, names[i]);
+ gtk_widget_set_sensitive (GTK_WIDGET(w), running_p);
}
}
+/* When the File menu is de-posted after a "Restart Daemon" command,
+ the window underneath doesn't repaint for some reason. I guess this
+ is a bug in exposure handling in GTK or GDK. This works around it.
+ */
+static void
+force_dialog_repaint (state *s)
+{
+#if 1
+ /* Tell GDK to invalidate and repaint the whole window.
+ */
+ GdkWindow *w = s->toplevel_widget->window;
+ GdkRegion *region = gdk_region_new ();
+ GdkRectangle rect;
+ rect.x = rect.y = 0;
+ rect.width = rect.height = 32767;
+ gdk_region_union_with_rect (region, &rect);
+ gdk_window_invalidate_region (w, region, True);
+ gdk_region_destroy (region);
+ gdk_window_process_updates (w, True);
+#else
+ /* Force the server to send an exposure event by creating and then
+ destroying a window as a child of the top level shell.
+ */
+ Display *dpy = GDK_DISPLAY();
+ Window parent = GDK_WINDOW_XWINDOW (s->toplevel_widget->window);
+ Window w;
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, parent, &xgwa);
+ w = XCreateSimpleWindow (dpy, parent, 0, 0, xgwa.width, xgwa.height, 0,0,0);
+ XMapRaised (dpy, w);
+ XDestroyWindow (dpy, w);
+ XSync (dpy, False);
+#endif
+}
+
+
/* Even though we've given these text fields a maximum number of characters,
their default size is still about 30 characters wide -- so measure out
a string in their font, and resize them to just fit that.
static void
fix_text_entry_sizes (state *s)
{
-#ifdef FIXME
+ GtkWidget *w;
+
+# if 0 /* appears no longer necessary with Gtk 1.2.10 */
const char * const spinbuttons[] = {
"timeout_spinbutton", "cycle_spinbutton", "lock_spinbutton",
"dpms_standby_spinbutton", "dpms_suspend_spinbutton",
"-fade_spinbutton" };
int i;
int width = 0;
- GtkWidget *w;
for (i = 0; i < countof(spinbuttons); i++)
{
width = gdk_string_width (w->style->font, "mmmmmmmmmmmmmmmmmmmm");
gtk_widget_set_usize (w, width, -2);
- /* Now fix the height of the list.
+# endif /* 0 */
+
+ /* Now fix the height of the list widget:
+ make it default to being around 10 text-lines high instead of 4.
*/
+ w = GTK_WIDGET (name_to_widget (s, "list"));
{
int lines = 10;
int height;
int leading = 3; /* approximate is ok... */
int border = 2;
- w = GTK_WIDGET (name_to_widget (s, "list"));
+
+#ifdef HAVE_GTK2
+ PangoFontMetrics *pain =
+ pango_context_get_metrics (gtk_widget_get_pango_context (w),
+ w->style->font_desc,
+ gtk_get_default_language ());
+ height = PANGO_PIXELS (pango_font_metrics_get_ascent (pain) +
+ pango_font_metrics_get_descent (pain));
+#else /* !HAVE_GTK2 */
height = w->style->font->ascent + w->style->font->descent;
+#endif /* !HAVE_GTK2 */
+
height += leading;
height *= lines;
height += border * 2;
w = GTK_WIDGET (name_to_widget (s, "scroller"));
gtk_widget_set_usize (w, -2, height);
}
-#endif
}
#endif /* !HAVE_GTK2 */
\f
+#ifndef HAVE_GTK2
/* Work around a Gtk bug that causes label widgets to wrap text too early.
*/
gtk_widget_size_request (label, &req);
}
-
/* Feel the love. Thanks to Nat Friedman for finding this workaround.
*/
static void
gtk_widget_queue_resize (GTK_WIDGET (label));
}
+#endif /* !HAVE_GTK2 */
static void
populate_demo_window (state *s, int list_elt)
{
+ Display *dpy = GDK_DISPLAY();
saver_preferences *p = &s->prefs;
screenhack *hack;
char *pretty_name;
}
else
{
- int hack_number = (list_elt >= 0 && list_elt < p->screenhacks_count
+ int hack_number = (list_elt >= 0 && list_elt < s->list_count
? s->list_elt_to_hack_number[list_elt]
: -1);
hack = (hack_number >= 0 ? p->screenhacks[hack_number] : 0);
pretty_name = (hack
? (hack->name
? strdup (hack->name)
- : make_hack_name (hack->command))
+ : make_hack_name (dpy, hack->command))
: 0);
if (hack)
if (!pretty_name)
pretty_name = strdup (_("Preview"));
- gtk_frame_set_label (frame1, pretty_name);
- gtk_frame_set_label (frame2, pretty_name);
+ gtk_frame_set_label (frame1, _(pretty_name));
+ gtk_frame_set_label (frame2, _(pretty_name));
gtk_entry_set_text (cmd, (hack ? hack->command : ""));
gtk_entry_set_position (cmd, 0);
{
char title[255];
- sprintf (title, "%s: %.100s Settings",
+ sprintf (title, _("%s: %.100s Settings"),
progclass, (pretty_name ? pretty_name : "???"));
gtk_window_set_title (GTK_WINDOW (s->popup_widget), title);
}
if (a == b)
return 0;
else
- return strcmp (sort_hack_cmp_names_kludge[*(int *) a],
- sort_hack_cmp_names_kludge[*(int *) b]);
+ {
+ int aa = *(int *) a;
+ int bb = *(int *) b;
+ const char last[] = "\377\377\377\377\377\377\377\377\377\377\377";
+ return strcmp ((aa < 0 ? last : sort_hack_cmp_names_kludge[aa]),
+ (bb < 0 ? last : sort_hack_cmp_names_kludge[bb]));
+ }
}
static void
initialize_sort_map (state *s)
{
+ Display *dpy = GDK_DISPLAY();
saver_preferences *p = &s->prefs;
- int i;
+ int i, j;
if (s->list_elt_to_hack_number) free (s->list_elt_to_hack_number);
if (s->hack_number_to_list_elt) free (s->hack_number_to_list_elt);
+ if (s->hacks_available_p) free (s->hacks_available_p);
s->list_elt_to_hack_number = (int *)
calloc (sizeof(int), p->screenhacks_count + 1);
s->hack_number_to_list_elt = (int *)
calloc (sizeof(int), p->screenhacks_count + 1);
+ s->hacks_available_p = (Bool *)
+ calloc (sizeof(Bool), p->screenhacks_count + 1);
+ s->total_available = 0;
- /* Initialize table to 1:1 mapping */
+ /* Check which hacks actually exist on $PATH
+ */
for (i = 0; i < p->screenhacks_count; i++)
- s->list_elt_to_hack_number[i] = i;
+ {
+ screenhack *hack = p->screenhacks[i];
+ int on = on_path_p (hack->command) ? 1 : 0;
+ s->hacks_available_p[i] = on;
+ s->total_available += on;
+ }
- /* Generate list of names (once)
+ /* Initialize list->hack table to unsorted mapping, omitting nonexistent
+ hacks, if desired.
+ */
+ j = 0;
+ for (i = 0; i < p->screenhacks_count; i++)
+ {
+ if (!p->ignore_uninstalled_p ||
+ s->hacks_available_p[i])
+ s->list_elt_to_hack_number[j++] = i;
+ }
+ s->list_count = j;
+
+ for (; j < p->screenhacks_count; j++)
+ s->list_elt_to_hack_number[j] = -1;
+
+
+ /* Generate list of sortable names (once)
*/
sort_hack_cmp_names_kludge = (char **)
calloc (sizeof(char *), p->screenhacks_count);
screenhack *hack = p->screenhacks[i];
char *name = (hack->name && *hack->name
? strdup (hack->name)
- : make_hack_name (hack->command));
+ : make_hack_name (dpy, hack->command));
char *str;
for (str = name; *str; str++)
*str = tolower(*str);
sort_hack_cmp_names_kludge[i] = name;
}
- /* Sort alphabetically
+ /* Sort list->hack map alphabetically
*/
qsort (s->list_elt_to_hack_number,
p->screenhacks_count,
/* Build inverse table */
for (i = 0; i < p->screenhacks_count; i++)
- s->hack_number_to_list_elt[s->list_elt_to_hack_number[i]] = i;
+ {
+ int n = s->list_elt_to_hack_number[i];
+ if (n != -1)
+ s->hack_number_to_list_elt[n] = i;
+ }
}
static int
maybe_reload_init_file (state *s)
{
+ Display *dpy = GDK_DISPLAY();
saver_preferences *p = &s->prefs;
int status = 0;
warning_dialog (s->toplevel_widget, b, False, 100);
free (b);
- load_init_file (p);
+ load_init_file (dpy, p);
initialize_sort_map (s);
list_elt = selected_list_element (s);
gdk_window_set_background (window, &p->style->bg[GTK_STATE_NORMAL]);
gdk_window_clear (window);
-#ifdef HAVE_GTK2
{
- GtkWidget *notebook;
+ int list_elt = selected_list_element (s);
+ int hack_number = (list_elt >= 0
+ ? s->list_elt_to_hack_number[list_elt]
+ : -1);
+ Bool available_p = (hack_number >= 0
+ ? s->hacks_available_p [hack_number]
+ : True);
+ Bool nothing_p = (s->total_available < 5);
- notebook = name_to_widget (s, "preview_notebook");
+#ifdef HAVE_GTK2
+ GtkWidget *notebook = name_to_widget (s, "preview_notebook");
gtk_notebook_set_page (GTK_NOTEBOOK (notebook),
- s->running_preview_error_p
- ? 1 : 0);
- }
+ (s->running_preview_error_p
+ ? (available_p ? 1 :
+ nothing_p ? 3 : 2)
+ : 0));
#else /* !HAVE_GTK2 */
- if (s->running_preview_error_p)
- {
- const char * const lines[] = { N_("No Preview"), N_("Available") };
- int lh = p->style->font->ascent + p->style->font->descent;
- int y, i;
- gint w, h;
- gdk_window_get_size (window, &w, &h);
- y = (h - (lh * countof(lines))) / 2;
- y += p->style->font->ascent;
- for (i = 0; i < countof(lines); i++)
- {
- int sw = gdk_string_width (p->style->font, _(lines[i]));
- int x = (w - sw) / 2;
- gdk_draw_string (window, p->style->font,
- p->style->fg_gc[GTK_STATE_NORMAL],
- x, y, _(lines[i]));
- y += lh;
- }
- }
+ if (s->running_preview_error_p)
+ {
+ const char * const lines1[] = { N_("No Preview"), N_("Available") };
+ const char * const lines2[] = { N_("Not"), N_("Installed") };
+ int nlines = countof(lines1);
+ int lh = p->style->font->ascent + p->style->font->descent;
+ int y, i;
+ gint w, h;
+
+ const char * const *lines = (available_p ? lines1 : lines2);
+
+ gdk_window_get_size (window, &w, &h);
+ y = (h - (lh * nlines)) / 2;
+ y += p->style->font->ascent;
+ for (i = 0; i < nlines; i++)
+ {
+ int sw = gdk_string_width (p->style->font, _(lines[i]));
+ int x = (w - sw) / 2;
+ gdk_draw_string (window, p->style->font,
+ p->style->fg_gc[GTK_STATE_NORMAL],
+ x, y, _(lines[i]));
+ y += lh;
+ }
+ }
#endif /* !HAVE_GTK2 */
+ }
gdk_flush ();
}
+static void
+reset_preview_window (state *s)
+{
+ /* On some systems (most recently, MacOS X) OpenGL programs get confused
+ when you kill one and re-start another on the same window. So maybe
+ it's best to just always destroy and recreate the preview window
+ when changing hacks, instead of always trying to reuse the same one?
+ */
+ GtkWidget *pr = name_to_widget (s, "preview");
+ if (GTK_WIDGET_REALIZED (pr))
+ {
+ Window oid = (pr->window ? GDK_WINDOW_XWINDOW (pr->window) : 0);
+ Window id;
+ gtk_widget_hide (pr);
+ gtk_widget_unrealize (pr);
+ gtk_widget_realize (pr);
+ gtk_widget_show (pr);
+ id = (pr->window ? GDK_WINDOW_XWINDOW (pr->window) : 0);
+ if (s->debug_p)
+ fprintf (stderr, "%s: window id 0x%X -> 0x%X\n", blurb(),
+ (unsigned int) oid,
+ (unsigned int) id);
+ }
+}
+
+
static void
fix_preview_visual (state *s)
{
style->fg_gc[GTK_STATE_NORMAL] = fgc;
style->bg_gc[GTK_STATE_NORMAL] = fgc;
gtk_widget_set_style (widget, style);
+
+ /* For debugging purposes, put a title on the window (so that
+ it can be easily found in the output of "xwininfo -tree".)
+ */
+ gdk_window_set_title (window, "Preview");
}
gtk_widget_show (widget);
char *ss = strchr (ps, ' ');
if (ss) *ss = 0;
ss = strrchr (ps, '/');
- if (ss) *ss = 0;
- else ss = ps;
+ if (!ss)
+ ss = ps;
+ else
+ {
+ ss = strdup (ss+1);
+ free (ps);
+ }
return ss;
}
else
if (pid == s->running_preview_pid)
{
char *ss = subproc_pretty_name (s);
- fprintf (stderr, "%s: pid %lu (%s) died\n", blurb(), pid, ss);
+ fprintf (stderr, "%s: pid %lu (%s) died\n", blurb(),
+ (unsigned long) pid, ss);
free (ss);
}
else
- fprintf (stderr, "%s: pid %lu died\n", blurb(), pid);
+ fprintf (stderr, "%s: pid %lu died\n", blurb(),
+ (unsigned long) pid);
}
}
}
sprintf (buf, "%s: running %s", blurb(), av[0]);
perror (buf);
}
- exit (1); /* exits fork */
+
+ /* Note that one must use _exit() instead of exit() in procs forked
+ off of Gtk programs -- Gtk installs an atexit handler that has a
+ copy of the X connection (which we've already closed, for safety.)
+ If one uses exit() instead of _exit(), then one sometimes gets a
+ spurious "Gdk-ERROR: Fatal IO error on X server" error message.
+ */
+ _exit (1); /* exits fork */
break;
}
default:
int wait_status = 0;
FILE *f = fdopen (in, "r");
- unsigned long v = 0;
+ unsigned int v = 0;
char c;
close (out); /* don't need this one */
*buf = 0;
- fgets (buf, sizeof(buf)-1, f);
+ if (!fgets (buf, sizeof(buf)-1, f))
+ *buf = 0;
fclose (f);
/* Wait for the child to die. */
static void
-kill_preview_subproc (state *s)
+kill_preview_subproc (state *s, Bool reset_p)
{
s->running_preview_error_p = False;
{
if (s->debug_p)
fprintf (stderr, "%s: pid %lu (%s) was already dead.\n",
- blurb(), s->running_preview_pid, ss);
+ blurb(), (unsigned long) s->running_preview_pid, ss);
}
else
{
char buf [1024];
sprintf (buf, "%s: couldn't kill pid %lu (%s)",
- blurb(), s->running_preview_pid, ss);
+ blurb(), (unsigned long) s->running_preview_pid, ss);
perror (buf);
}
}
- else if (s->debug_p)
- fprintf (stderr, "%s: killed pid %lu (%s)\n", blurb(),
- s->running_preview_pid, ss);
+ else {
+ int endstatus;
+ waitpid(s->running_preview_pid, &endstatus, 0);
+ if (s->debug_p)
+ fprintf (stderr, "%s: killed pid %lu (%s)\n", blurb(),
+ (unsigned long) s->running_preview_pid, ss);
+ }
free (ss);
s->running_preview_pid = 0;
}
reap_zombies (s);
+
+ if (reset_p)
+ {
+ reset_preview_window (s);
+ clear_preview_window (s);
+ }
}
const char *cmd = s->desired_preview_cmd;
GtkWidget *pr = name_to_widget (s, "preview");
- GdkWindow *window = pr->window;
+ GdkWindow *window;
+
+ reset_preview_window (s);
+
+ window = pr->window;
s->running_preview_error_p = False;
if (s->preview_suppressed_p)
{
- kill_preview_subproc (s);
+ kill_preview_subproc (s, False);
goto DONE;
}
else
{
strcpy (new_cmd, cmd);
- sprintf (new_cmd + strlen (new_cmd), " -window-id 0x%X", id);
+ sprintf (new_cmd + strlen (new_cmd), " -window-id 0x%X",
+ (unsigned int) id);
}
- kill_preview_subproc (s);
+ kill_preview_subproc (s, False);
if (! new_cmd)
{
s->running_preview_error_p = True;
{
close (ConnectionNumber (GDK_DISPLAY()));
+ hack_subproc_environment (id, s->debug_p);
+
usleep (250000); /* pause for 1/4th second before launching, to give
the previous program time to die and flush its X
buffer, so we don't get leftover turds on the
exec_command (p->shell, new_cmd, p->nice_inferior);
/* Don't bother printing an error message when we are unable to
- exec subprocesses; we handle that by polling the pid later. */
- exit (1); /* exits child fork */
+ exec subprocesses; we handle that by polling the pid later.
+
+ Note that one must use _exit() instead of exit() in procs forked
+ off of Gtk programs -- Gtk installs an atexit handler that has a
+ copy of the X connection (which we've already closed, for safety.)
+ If one uses exit() instead of _exit(), then one sometimes gets a
+ spurious "Gdk-ERROR: Fatal IO error on X server" error message.
+ */
+ _exit (1); /* exits child fork */
break;
default:
if (s->debug_p)
{
char *ss = subproc_pretty_name (s);
- fprintf (stderr, "%s: forked %lu (%s)\n", blurb(), forked, ss);
+ fprintf (stderr, "%s: forked %lu (%s)\n", blurb(),
+ (unsigned long) forked, ss);
free (ss);
}
break;
}
+static void
+hack_subproc_environment (Window preview_window_id, Bool debug_p)
+{
+ /* Store a window ID in $XSCREENSAVER_WINDOW -- this isn't strictly
+ necessary yet, but it will make programs work if we had invoked
+ them with "-root" and not with "-window-id" -- which, of course,
+ doesn't happen.
+ */
+ char *nssw = (char *) malloc (40);
+ sprintf (nssw, "XSCREENSAVER_WINDOW=0x%X", (unsigned int) preview_window_id);
+
+ /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
+ any more, right? It's not Posix, but everyone seems to have it. */
+ if (putenv (nssw))
+ abort ();
+
+ if (debug_p)
+ fprintf (stderr, "%s: %s\n", blurb(), nssw);
+
+ /* do not free(nssw) -- see above */
+}
+
+
/* Called from a timer:
Launches the currently-chosen subprocess, if it's not already running.
If there's a different process running, kills it.
{
state *s = (state *) data;
if (! s->desired_preview_cmd)
- kill_preview_subproc (s);
+ kill_preview_subproc (s, True);
else if (!s->running_preview_cmd ||
!!strcmp (s->desired_preview_cmd, s->running_preview_cmd))
launch_preview_subproc (s);
{
char *ss = subproc_pretty_name (s);
fprintf (stderr, "%s: timer: pid %lu (%s) is %s\n", blurb(),
- s->running_preview_pid, ss,
+ (unsigned long) s->running_preview_pid, ss,
(s->running_preview_error_p ? "dead" : "alive"));
free (ss);
}
Atom type;
int format;
unsigned long nitems, bytesafter;
- CARD32 *data = 0;
+ unsigned char *dataP = 0;
Display *dpy = GDK_DISPLAY();
Bool blanked_p = False;
XA_SCREENSAVER_STATUS,
0, 3, False, XA_INTEGER,
&type, &format, &nitems, &bytesafter,
- (unsigned char **) &data)
+ &dataP)
== Success
&& type == XA_INTEGER
&& nitems >= 3
- && data)
- blanked_p = (data[0] == XA_BLANK || data[0] == XA_LOCK);
+ && dataP)
+ {
+ Atom *data = (Atom *) dataP;
+ blanked_p = (data[0] == XA_BLANK || data[0] == XA_LOCK);
+ }
- if (data) free (data);
+ if (dataP) XFree (dataP);
return blanked_p;
}
{
if (s->debug_p)
fprintf (stderr, "%s: screen is blanked: killing preview\n", blurb());
- kill_preview_subproc (s);
+ kill_preview_subproc (s, True);
}
return True; /* re-execute timer */
}
+
+/* How many screens are there (including Xinerama.)
+ */
+static int
+screen_count (Display *dpy)
+{
+ int nscreens = ScreenCount(dpy);
+# ifdef HAVE_XINERAMA
+ if (nscreens <= 1)
+ {
+ int event_number, error_number;
+ if (XineramaQueryExtension (dpy, &event_number, &error_number) &&
+ XineramaIsActive (dpy))
+ {
+ XineramaScreenInfo *xsi = XineramaQueryScreens (dpy, &nscreens);
+ if (xsi) XFree (xsi);
+ }
+ }
+# endif /* HAVE_XINERAMA */
+
+ return nscreens;
+}
+
\f
/* Setting window manager icon
*/
"xscreensaver as \"%s\".\n"
"\n"
"Restart the xscreensaver daemon now?\n"),
- blurb(), luser, lhost,
+ progname, luser, lhost,
d,
(ruser ? ruser : "???"), (rhost ? rhost : "???"),
- blurb(),
- blurb(), (ruser ? ruser : "???"),
+ progname,
+ progname, (ruser ? ruser : "???"),
luser);
}
else if (rhost && *rhost && !!strcmp (rhost, lhost))
"%s won't work right.\n"
"\n"
"Restart the daemon on \"%s\" as \"%s\" now?\n"),
- blurb(), luser, lhost,
+ progname, luser, lhost,
d,
(ruser ? ruser : "???"), (rhost ? rhost : "???"),
luser,
- blurb(),
+ progname,
lhost, luser);
}
else if (!!strcmp (rversion, s->short_version))
state *s = global_state_kludge; /* I hate C so much... */
fprintf (stderr, "\nX error in %s:\n", blurb());
XmuPrintDefaultErrorMessage (dpy, error, stderr);
- kill_preview_subproc (s);
+ kill_preview_subproc (s, False);
exit (-1);
return 0;
}
}
+#ifdef __GNUC__
+ __extension__ /* shut up about "string length is greater than the length
+ ISO C89 compilers are required to support" when including
+ the .ad file... */
+#endif
+
static char *defaults[] = {
#include "XScreenSaver_ad.h"
0
# ifdef HAVE_CRAPPLET
" [--crapplet]"
# endif
- "\n\t\t [--debug] [--sync] [--no-xshm]";
+ "\n\t\t [--debug] [--sync] [--no-xshm] [--configdir dir]";
static void
map_popup_window_cb (GtkWidget *w, gpointer user_data)
{
state *s = (state *) user_data;
Boolean oi = s->initializing_p;
+#ifndef HAVE_GTK2
GtkLabel *label = GTK_LABEL (name_to_widget (s, "doc"));
+#endif
s->initializing_p = True;
+#ifndef HAVE_GTK2
eschew_gtk_lossage (label);
+#endif
s->initializing_p = oi;
}
Display *dpy;
Widget toplevel_shell;
char *real_progname = argv[0];
- char window_title[255];
+ char *window_title;
+ char *geom = 0;
Bool crapplet_p = False;
char *str;
/* 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")))
- {
+ {
+ if (argv[i] &&
+ (!strcmp(argv[i], "--crapplet") ||
+ !strcmp(argv[i], "--capplet")))
+ {
# if defined(HAVE_CRAPPLET) || defined(HAVE_GTK2)
- int j;
- crapplet_p = True;
- for (j = i; j < argc; j++) /* remove it from the list */
- argv[j] = argv[j+1];
- argc--;
+ 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 && !HAVE_GTK2 */
- fprintf (stderr, "%s: not compiled with --crapplet support\n",
- real_progname);
- fprintf (stderr, "%s: %s\n", real_progname, usage);
- exit (1);
+ fprintf (stderr, "%s: not compiled with --crapplet support\n",
+ real_progname);
+ fprintf (stderr, "%s: %s\n", real_progname, usage);
+ exit (1);
# endif /* !HAVE_CRAPPLET && !HAVE_GTK2 */
- }
- else if (argv[i] &&
- (!strcmp(argv[i], "--debug") ||
- !strcmp(argv[i], "-debug") ||
- !strcmp(argv[i], "-d")))
- {
- int j;
- s->debug_p = True;
- for (j = i; j < argc; j++) /* remove it from the list */
- argv[j] = argv[j+1];
- argc--;
+ }
+ else if (argv[i] &&
+ (!strcmp(argv[i], "--debug") ||
+ !strcmp(argv[i], "-debug") ||
+ !strcmp(argv[i], "-d")))
+ {
+ int j;
+ s->debug_p = True;
+ for (j = i; j < argc; j++) /* remove it from the list */
+ argv[j] = argv[j+1];
+ argc--;
+ i--;
+ }
+ else if (argv[i] &&
+ argc > i+1 &&
+ *argv[i+1] &&
+ (!strcmp(argv[i], "-geometry") ||
+ !strcmp(argv[i], "-geom") ||
+ !strcmp(argv[i], "-geo") ||
+ !strcmp(argv[i], "-g")))
+ {
+ int j;
+ geom = argv[i+1];
+ for (j = i; j < argc; j++) /* remove them from the list */
+ argv[j] = argv[j+2];
+ argc -= 2;
+ i -= 2;
+ }
+ else if (argv[i] &&
+ argc > i+1 &&
+ *argv[i+1] &&
+ (!strcmp(argv[i], "--configdir")))
+ {
+ int j;
+ struct stat st;
+ hack_configuration_path = argv[i+1];
+ for (j = i; j < argc; j++) /* remove them from the list */
+ argv[j] = argv[j+2];
+ argc -= 2;
+ i -= 2;
+
+ if (0 != stat (hack_configuration_path, &st))
+ {
+ char buf[255];
+ sprintf (buf, "%s: %.200s", blurb(), hack_configuration_path);
+ perror (buf);
+ exit (1);
+ }
+ else if (!S_ISDIR (st.st_mode))
+ {
+ fprintf (stderr, "%s: not a directory: %s\n",
+ blurb(), hack_configuration_path);
+ exit (1);
+ }
+ }
}
+
+ if (s->debug_p)
+ fprintf (stderr, "%s: using config directory \"%s\"\n",
+ progname, hack_configuration_path);
+
+
/* Let Gtk open the X connection, then initialize Xt to use that
same connection. Doctor Frankenstein would be proud.
*/
;
else
{
- fprintf (stderr, _("%s: unknown option: %s\n"), real_progname, argv[i]);
+ fprintf (stderr, _("%s: unknown option: %s\n"), real_progname,
+ argv[i]);
fprintf (stderr, "%s: %s\n", real_progname, usage);
exit (1);
}
was in argv[0].
*/
p->db = db;
- load_init_file (p);
+ s->nscreens = screen_count (dpy);
+
+ hack_environment (s); /* must be before initialize_sort_map() */
+
+ load_init_file (dpy, p);
initialize_sort_map (s);
/* Now that Xt has been initialized, and the resources have been read,
/* Set the main window's title. */
{
+ char *base_title = _("Screensaver Preferences");
char *v = (char *) strdup(strchr(screensaver_id, ' '));
char *s1, *s2, *s3, *s4;
s1 = (char *) strchr(v, ' '); s1++;
s4 = (char *) strchr(s3, ')');
*s2 = 0;
*s4 = 0;
- sprintf (window_title, "%.50s %.50s, %.50s", progclass, s1, s3);
+
+ window_title = (char *) malloc (strlen (base_title) +
+ strlen (progclass) +
+ strlen (s1) + strlen (s3) +
+ 100);
+ sprintf (window_title, "%s (%s %s, %s)", base_title, progclass, s1, s3);
gtk_window_set_title (GTK_WINDOW (s->toplevel_widget), window_title);
gtk_window_set_title (GTK_WINDOW (s->popup_widget), window_title);
free (v);
GtkOptionMenu *opt = GTK_OPTION_MENU (name_to_widget (s, "mode_menu"));
GtkMenu *menu = GTK_MENU (gtk_option_menu_get_menu (opt));
GList *kids = gtk_container_children (GTK_CONTAINER (menu));
- for (; kids; kids = kids->next)
- gtk_signal_connect (GTK_OBJECT (kids->data), "activate",
- GTK_SIGNAL_FUNC (mode_menu_item_cb),
- (gpointer) s);
+ int i;
+ for (i = 0; kids; kids = kids->next, i++)
+ {
+ gtk_signal_connect (GTK_OBJECT (kids->data), "activate",
+ GTK_SIGNAL_FUNC (mode_menu_item_cb),
+ (gpointer) s);
+
+ /* The "random-same" mode menu item does not appear unless
+ there are multple screens.
+ */
+ if (s->nscreens <= 1 &&
+ mode_menu_order[i] == RANDOM_HACKS_SAME)
+ gtk_widget_hide (GTK_WIDGET (kids->data));
+ }
+
+ if (s->nscreens <= 1) /* recompute option-menu size */
+ {
+ gtk_widget_unrealize (GTK_WIDGET (menu));
+ gtk_widget_realize (GTK_WIDGET (menu));
+ }
}
# ifdef HAVE_CRAPPLET_IMMEDIATE
capplet_widget_changes_are_immediate (CAPPLET_WIDGET (capplet));
# endif /* HAVE_CRAPPLET_IMMEDIATE */
-
/* In crapplet-mode, take off the menubar. */
gtk_widget_hide (name_to_widget (s, "menubar"));
gtk_widget_ref (outer_vbox);
gtk_container_remove (GTK_CONTAINER (s->toplevel_widget),
outer_vbox);
- GTK_OBJECT_SET_FLAGS (outer_vbox, GTK_FLOATING);
+ STFU GTK_OBJECT_SET_FLAGS (outer_vbox, GTK_FLOATING);
gtk_container_add (GTK_CONTAINER (capplet), outer_vbox);
/* Find the window above us, and set the title and close handler. */
# endif /* HAVE_CRAPPLET */
+ /* The Gnome folks hate the menubar. I think it's important to have access
+ to the commands on the File menu (Restart Daemon, etc.) and to the
+ About and Documentation commands on the Help menu.
+ */
+#if 0
+#ifdef HAVE_GTK2
+ gtk_widget_hide (name_to_widget (s, "menubar"));
+#endif
+#endif
+
+ free (window_title);
+ window_title = 0;
+
+#ifdef HAVE_GTK2
+ /* After picking the default size, allow -geometry to override it. */
+ if (geom)
+ gtk_window_parse_geometry (GTK_WINDOW (s->toplevel_widget), geom);
+#endif
+
gtk_widget_show (s->toplevel_widget);
init_icon (GTK_WIDGET (s->toplevel_widget)->window); /* after `show' */
- hack_environment (s);
fix_preview_visual (s);
/* Realize page zero, so that we can diddle the scrollbar when the
/* Issue any warnings about the running xscreensaver daemon. */
- the_network_is_not_the_computer (s);
+ if (! s->debug_p)
+ the_network_is_not_the_computer (s);
/* Run the Gtk event loop, and not the Xt event loop. This means that
gtk_timeout_add (500, delayed_scroll_kludge, s);
-#if 0
+#if 1
/* Load every configurator in turn, to scan them for errors all at once. */
- {
- int i;
- for (i = 0; i < p->screenhacks_count; i++)
- {
- screenhack *hack = p->screenhacks[s->hack_number_to_list_elt[i]];
- conf_data *d = load_configurator (hack->command, False);
- if (d) free_conf_data (d);
- }
- }
+ if (s->debug_p)
+ {
+ int i;
+ for (i = 0; i < p->screenhacks_count; i++)
+ {
+ screenhack *hack = p->screenhacks[i];
+ conf_data *d = load_configurator (hack->command, s->debug_p);
+ if (d) free_conf_data (d);
+ }
+ }
#endif
# endif /* HAVE_CRAPPLET */
gtk_main ();
- kill_preview_subproc (s);
+ kill_preview_subproc (s, False);
exit (0);
}