X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fdemo-Gtk.c;h=f5c483965a3a8ead6947abc473d9ea4a823f1c29;hb=aa75c7476aeaa84cf3abc192b376a8b03c325213;hp=f9c066c3d81dc0c280350e8c1aeb42025ad49e3b;hpb=2d04c4f22466851aedb6ed0f2919d148f726b889;p=xscreensaver diff --git a/driver/demo-Gtk.c b/driver/demo-Gtk.c index f9c066c3..f5c48396 100644 --- a/driver/demo-Gtk.c +++ b/driver/demo-Gtk.c @@ -1,5 +1,5 @@ /* demo-Gtk.c --- implements the interactive demo-mode and options dialogs. - * xscreensaver, Copyright (c) 1993-2005 Jamie Zawinski + * xscreensaver, Copyright (c) 1993-2016 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -78,6 +78,10 @@ # include "xmu.h" #endif +#ifdef HAVE_XINERAMA +# include +#endif /* HAVE_XINERAMA */ + #include #ifdef HAVE_CRAPPLET @@ -119,11 +123,6 @@ #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" #include @@ -138,8 +137,44 @@ enum { }; #endif /* HAVE_GTK2 */ +/* Deal with deprecation of direct access to struct fields on the way to GTK3 + See http://live.gnome.org/GnomeGoals/UseGseal + */ +#if GTK_CHECK_VERSION(2,14,0) +# define GET_PARENT(w) gtk_widget_get_parent (w) +# define GET_WINDOW(w) gtk_widget_get_window (w) +# define GET_ACTION_AREA(d) gtk_dialog_get_action_area (d) +# define GET_CONTENT_AREA(d) gtk_dialog_get_content_area (d) +# define GET_ADJ_VALUE(a) gtk_adjustment_get_value (a) +# define SET_ADJ_VALUE(a,v) gtk_adjustment_set_value (a, v) +# define SET_ADJ_UPPER(a,v) gtk_adjustment_set_upper (a, v) +#else +# define GET_PARENT(w) ((w)->parent) +# define GET_WINDOW(w) ((w)->window) +# define GET_ACTION_AREA(d) ((d)->action_area) +# define GET_CONTENT_AREA(d) ((d)->vbox) +# define GET_ADJ_VALUE(a) ((a)->value) +# define SET_ADJ_VALUE(a,v) (a)->value = v +# define SET_ADJ_UPPER(a,v) (a)->upper = v +#endif + +#if GTK_CHECK_VERSION(2,18,0) +# define SET_CAN_DEFAULT(w) gtk_widget_set_can_default ((w), TRUE) +# define GET_SENSITIVE(w) gtk_widget_get_sensitive (w) +#else +# define SET_CAN_DEFAULT(w) GTK_WIDGET_SET_FLAGS ((w), GTK_CAN_DEFAULT) +# define GET_SENSITIVE(w) GTK_WIDGET_IS_SENSITIVE (w) +#endif + +#if GTK_CHECK_VERSION(2,20,0) +# define GET_REALIZED(w) gtk_widget_get_realized (w) +#else +# define GET_REALIZED(w) GTK_WIDGET_REALIZED (w) +#endif + /* 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); @@ -147,13 +182,20 @@ static void hack_subproc_environment (Window preview_window_id, Bool debug_p); #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 { @@ -186,6 +228,7 @@ 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. */ @@ -193,6 +236,8 @@ typedef struct { 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; @@ -217,16 +262,56 @@ static Bool flush_popup_changes_and_save (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 *, Bool reset_p); static void schedule_preview_check (state *); + +/* 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_reset_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); + +static void kill_gnome_screensaver (void); +static void kill_kde_screensaver (void); /* Some random utility functions */ +const char *blurb (void); + const char * blurb (void) { @@ -296,7 +381,8 @@ name_to_widget (state *s, const char *name) #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(); } @@ -371,9 +457,9 @@ ensure_selected_item_visible (GtkWidget *widget) adj = gtk_scrolled_window_get_vadjustment (scroller); - gdk_window_get_geometry (GTK_WIDGET(vp)->window, + gdk_window_get_geometry (GET_WINDOW (GTK_WIDGET (vp)), &ignore, &ignore, &ignore, &parent_h, &ignore); - gdk_window_get_geometry (GTK_WIDGET(selected)->window, + gdk_window_get_geometry (GET_WINDOW (GTK_WIDGET (selected)), &ignore, &child_y, &ignore, &child_h, &ignore); children_h = nkids * child_h; @@ -416,8 +502,8 @@ static void warning_dialog_dismiss_cb (GtkWidget *widget, gpointer user_data) { GtkWidget *shell = GTK_WIDGET (user_data); - while (shell->parent) - shell = shell->parent; + while (GET_PARENT (shell)) + shell = GET_PARENT (shell); gtk_widget_destroy (GTK_WIDGET (shell)); } @@ -430,9 +516,23 @@ static void warning_dialog_restart_cb (GtkWidget *widget, gpointer user_data) warning_dialog_dismiss_cb (widget, user_data); } -static void +static void warning_dialog_killg_cb (GtkWidget *widget, gpointer user_data) +{ + kill_gnome_screensaver (); + warning_dialog_dismiss_cb (widget, user_data); +} + +static void warning_dialog_killk_cb (GtkWidget *widget, gpointer user_data) +{ + kill_kde_screensaver (); + warning_dialog_dismiss_cb (widget, user_data); +} + +typedef enum { D_NONE, D_LAUNCH, D_GNOME, D_KDE } dialog_button; + +static Bool warning_dialog (GtkWidget *parent, const char *message, - Boolean restart_button_p, int center) + dialog_button button_type, int center) { char *msg = strdup (message); char *head; @@ -443,14 +543,15 @@ warning_dialog (GtkWidget *parent, const char *message, GtkWidget *cancel = 0; int i = 0; - while (parent && !parent->window) - parent = parent->parent; + while (parent && !GET_WINDOW (parent)) + parent = GET_PARENT (parent); if (!parent || - !GTK_WIDGET (parent)->window) /* too early to pop up transient dialogs */ + !GET_WINDOW (parent)) /* too early to pop up transient dialogs */ { fprintf (stderr, "%s: too early for dialog?\n", progname); - return; + free(msg); + return False; } head = msg; @@ -482,7 +583,7 @@ warning_dialog (GtkWidget *parent, const char *message, #endif /* !HAVE_GTK2 */ 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 (GET_CONTENT_AREA (GTK_DIALOG (dialog))), label, TRUE, TRUE, 0); gtk_widget_show (label); } @@ -496,16 +597,16 @@ warning_dialog (GtkWidget *parent, const char *message, } label = gtk_label_new (""); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))), label, TRUE, TRUE, 0); gtk_widget_show (label); label = gtk_hbutton_box_new (); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), + gtk_box_pack_start (GTK_BOX (GET_ACTION_AREA (GTK_DIALOG (dialog))), label, TRUE, TRUE, 0); #ifdef HAVE_GTK2 - if (restart_button_p) + if (button_type != D_NONE) { cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); gtk_container_add (GTK_CONTAINER (label), cancel); @@ -519,7 +620,7 @@ warning_dialog (GtkWidget *parent, const char *message, ok = gtk_button_new_with_label ("OK"); gtk_container_add (GTK_CONTAINER (label), ok); - if (restart_button_p) + if (button_type != D_NONE) { cancel = gtk_button_new_with_label ("Cancel"); gtk_container_add (GTK_CONTAINER (label), cancel); @@ -530,22 +631,28 @@ warning_dialog (GtkWidget *parent, const char *message, 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); - STFU GTK_WIDGET_SET_FLAGS (ok, GTK_CAN_DEFAULT); + SET_CAN_DEFAULT (ok); gtk_widget_show (ok); gtk_widget_grab_focus (ok); if (cancel) { - STFU GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT); + SET_CAN_DEFAULT (cancel); gtk_widget_show (cancel); } gtk_widget_show (label); gtk_widget_show (dialog); - if (restart_button_p) + if (button_type != D_NONE) { - gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", - GTK_SIGNAL_FUNC (warning_dialog_restart_cb), + GtkSignalFunc fn; + switch (button_type) { + case D_LAUNCH: fn = GTK_SIGNAL_FUNC (warning_dialog_restart_cb); break; + case D_GNOME: fn = GTK_SIGNAL_FUNC (warning_dialog_killg_cb); break; + case D_KDE: fn = GTK_SIGNAL_FUNC (warning_dialog_killk_cb); break; + default: abort(); break; + } + gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", fn, (gpointer) dialog); gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked", GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb), @@ -558,8 +665,8 @@ warning_dialog (GtkWidget *parent, const char *message, (gpointer) dialog); } - gdk_window_set_transient_for (GTK_WIDGET (dialog)->window, - GTK_WIDGET (parent)->window); + gdk_window_set_transient_for (GET_WINDOW (GTK_WIDGET (dialog)), + GET_WINDOW (GTK_WIDGET (parent))); #ifdef HAVE_GTK2 gtk_window_present (GTK_WINDOW (dialog)); @@ -569,6 +676,7 @@ warning_dialog (GtkWidget *parent, const char *message, #endif /* !HAVE_GTK2 */ free (msg); + return True; } @@ -592,9 +700,12 @@ run_cmd (state *s, Atom command, int arg) sprintf (buf, "Error:\n\n%s", err); else strcpy (buf, "Unknown error!"); - warning_dialog (s->toplevel_widget, buf, False, 100); + warning_dialog (s->toplevel_widget, buf, D_NONE, 100); } if (err) free (err); + + sensitize_menu_items (s, True); + force_dialog_repaint (s); } @@ -602,20 +713,56 @@ static void 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, D_NONE, 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, D_LAUNCH, 1); + } } + + if (err) free (err); + + sensitize_menu_items (s, False); } @@ -651,23 +798,30 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data) { char msg [2048]; char *vers = strdup (screensaver_id + 4); - char *s; + char *s, *s2; char copy[1024]; - char *desc = _("For updates, check http://www.jwz.org/xscreensaver/"); + char year[5]; + char *desc = _("For updates, check https://www.jwz.org/xscreensaver/"); s = strchr (vers, ','); *s = 0; s += 2; + s2 = vers; + s2 = strrchr (vers, '-'); + s2++; + strncpy (year, s2, 4); + year[4] = 0; + /* Ole Laursen 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-2005 %s"), s); + sprintf(copy, ("Copyright \xC2\xA9 1991-%s %s"), year, s); #else /* !HAVE_GTK2 */ - sprintf(copy, ("Copyright \251 1991-2005 %s"), s); + sprintf(copy, ("Copyright \251 1991-%s %s"), year, s); #endif /* !HAVE_GTK2 */ sprintf (msg, "%s\n\n%s", copy, desc); @@ -694,11 +848,11 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data) GtkWidget *dialog = gtk_dialog_new (); GtkWidget *hbox, *icon, *vbox, *label1, *label2, *hb, *ok; GtkWidget *parent = GTK_WIDGET (menuitem); - while (parent->parent) - parent = parent->parent; + while (GET_PARENT (parent)) + parent = GET_PARENT (parent); hbox = gtk_hbox_new (FALSE, 20); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))), hbox, TRUE, TRUE, 0); colormap = gtk_widget_get_colormap (parent); @@ -739,7 +893,7 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data) hb = gtk_hbutton_box_new (); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), + gtk_box_pack_start (GTK_BOX (GET_ACTION_AREA (GTK_DIALOG (dialog))), hb, TRUE, TRUE, 0); #ifdef HAVE_GTK2 @@ -765,10 +919,10 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data) 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); - gdk_window_show (GTK_WIDGET (dialog)->window); - gdk_window_raise (GTK_WIDGET (dialog)->window); + gdk_window_set_transient_for (GET_WINDOW (GTK_WIDGET (dialog)), + GET_WINDOW (GTK_WIDGET (parent))); + gdk_window_show (GET_WINDOW (GTK_WIDGET (dialog))); + gdk_window_raise (GET_WINDOW (GTK_WIDGET (dialog))); } } @@ -784,7 +938,7 @@ doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data) { warning_dialog (s->toplevel_widget, _("Error:\n\n" - "No Help URL has been specified.\n"), False, 100); + "No Help URL has been specified.\n"), D_NONE, 100); return; } @@ -795,11 +949,20 @@ doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data) 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); } +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) { @@ -831,38 +994,39 @@ restart_menu_cb (GtkWidget *widget, gpointer user_data) 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 void -await_xscreensaver (state *s) +static Bool +xscreensaver_running_p (state *s) { - int countdown = 5; - Display *dpy = GDK_DISPLAY(); - /* GtkWidget *dialog = 0;*/ char *rversion = 0; + server_xscreensaver_version (dpy, &rversion, 0, 0); + if (!rversion) + return False; + free (rversion); + return True; +} - while (!rversion && (--countdown > 0)) - { - /* Check for the version of the running xscreensaver... */ - server_xscreensaver_version (dpy, &rversion, 0, 0); +static void +await_xscreensaver (state *s) +{ + int countdown = 5; + Bool ok = False; - /* If it's not there yet, wait a second... */ - if (!rversion) - sleep (1); - } + while (!ok && (--countdown > 0)) + if (xscreensaver_running_p (s)) + ok = True; + else + sleep (1); /* If it's not there yet, wait a second... */ -/* if (dialog) gtk_widget_destroy (dialog);*/ + sensitize_menu_items (s, True); - if (rversion) - { - /* Got it. */ - free (rversion); - } - else + if (! ok) { /* Timed out, no screensaver running. */ @@ -881,7 +1045,7 @@ await_xscreensaver (state *s) the length ISO C89 compilers are required to support" in the following expression... */ # endif - strcat (buf, + strcat (buf, STFU _("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" @@ -900,8 +1064,10 @@ await_xscreensaver (state *s) else strcat (buf, _("Please check your $PATH and permissions.")); - warning_dialog (s->toplevel_widget, buf, False, 1); + warning_dialog (s->toplevel_widget, buf, D_NONE, 1); } + + force_dialog_repaint (s); } @@ -915,6 +1081,7 @@ selected_list_element (state *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... */ @@ -922,7 +1089,7 @@ demo_write_init_file (state *s, saver_preferences *p) 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()); @@ -934,12 +1101,12 @@ demo_write_init_file (state *s, saver_preferences *p) if (!f || !*f) warning_dialog (s->toplevel_widget, _("Error:\n\nCouldn't determine init file name!\n"), - False, 100); + D_NONE, 100); else { char *b = (char *) malloc (strlen(f) + 1024); sprintf (b, _("Error:\n\nCouldn't write %s\n"), f); - warning_dialog (s->toplevel_widget, b, False, 100); + warning_dialog (s->toplevel_widget, b, D_NONE, 100); free (b); } return -1; @@ -961,12 +1128,14 @@ run_this_cb (GtkButton *button, gpointer user_data) 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; 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]; @@ -975,14 +1144,15 @@ manual_cb (GtkButton *button, gpointer user_data) 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) * 4) + 100); @@ -991,17 +1161,18 @@ manual_cb (GtkButton *button, gpointer user_data) cmd, name2, name2, name2, name2); strcat (cmd2, " ) &"); - system (cmd2); + if (system (cmd2) < 0) + fprintf (stderr, "%s: fork error\n", blurb()); free (cmd2); } else { warning_dialog (GTK_WIDGET (button), _("Error:\n\nno `manualCommand' resource set."), - False, 100); + D_NONE, 100); } - free (name); + free (oname); } @@ -1009,7 +1180,7 @@ static void force_list_select_item (state *s, GtkWidget *list, int list_elt, Bool scroll_p) { GtkWidget *parent = name_to_widget (s, "scroller"); - Bool was = GTK_WIDGET_IS_SENSITIVE (parent); + gboolean was = GET_SENSITIVE (parent); #ifdef HAVE_GTK2 GtkTreeIter iter; GtkTreeModel *model; @@ -1019,10 +1190,12 @@ force_list_select_item (state *s, GtkWidget *list, int list_elt, Bool scroll_p) if (!was) gtk_widget_set_sensitive (parent, True); #ifdef HAVE_GTK2 model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); - STFU 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); + 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 */ @@ -1181,7 +1354,7 @@ hack_time_text (state *s, const char *line, Time *store, Bool sec_p) _("Error:\n\n" "Unparsable time format: \"%s\"\n"), line); - warning_dialog (s->toplevel_widget, b, False, 100); + warning_dialog (s->toplevel_widget, b, D_NONE, 100); } else *store = value; @@ -1203,6 +1376,20 @@ directory_p (const char *path) 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) { @@ -1228,19 +1415,32 @@ normalize_directory (const char *path) { s0--; s += 3; - strcpy (s0, s); + /* strcpy (s0, s); */ + memmove(s0, s, strlen(s) + 1); s = s0-1; } } - else if (*s == '/' && !strncmp (s, "/./", 3)) /* delete "/./" */ - strcpy (s, s+2), s--; + else if (*s == '/' && !strncmp (s, "/./", 3)) { /* delete "/./" */ + /* strcpy (s, s+2), s--; */ + memmove(s, s+2, strlen(s+2) + 1); + s--; + } else if (*s == '/' && !strncmp (s, "/.\000", 3)) /* delete "/.$" */ *s = 0, s--; } - for (s = p2; s && *s; s++) /* normalize consecutive slashes */ - while (s[0] == '/' && s[1] == '/') - strcpy (s, s+1); + /* + Normalize consecutive slashes. + Ignore doubled slashes after ":" to avoid mangling URLs. + */ + + for (s = p2; s && *s; s++){ + if (*s == ':') continue; + if (!s[1] || !s[2]) continue; + while (s[1] == '/' && s[2] == '/') + /* strcpy (s+1, s+2); */ + memmove (s+1, s+2, strlen(s+2) + 1); + } /* and strip trailing whitespace for good measure. */ L = strlen(p2); @@ -1302,6 +1502,7 @@ flush_dialog_changes_and_save (state *s) GList *kids = gtk_container_children (GTK_CONTAINER (list_widget)); int i; #endif /* !HAVE_GTK2 */ + static Bool already_warned_about_missing_image_directory = False; /* very long name... */ Bool changed = False; GtkWidget *w; @@ -1354,12 +1555,17 @@ flush_dialog_changes_and_save (state *s) 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 *) g_strdup(gtk_entry_get_text (GTK_ENTRY (w))) + MINUTES (&p2->timeout, "timeout_spinbutton"); MINUTES (&p2->cycle, "cycle_spinbutton"); CHECKBOX (p2->lock_p, "lock_button"); MINUTES (&p2->lock_timeout, "lock_spinbutton"); - CHECKBOX (p2->dpms_enabled_p, "dpms_button"); + CHECKBOX (p2->dpms_enabled_p, "dpms_button"); + CHECKBOX (p2->dpms_quickoff_p, "dpms_quickoff_button"); MINUTES (&p2->dpms_standby, "dpms_standby_spinbutton"); MINUTES (&p2->dpms_suspend, "dpms_suspend_spinbutton"); MINUTES (&p2->dpms_off, "dpms_off_spinbutton"); @@ -1369,9 +1575,25 @@ flush_dialog_changes_and_save (state *s) 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"); @@ -1382,17 +1604,30 @@ flush_dialog_changes_and_save (state *s) # undef MINUTES # undef CHECKBOX # undef PATHNAME +# undef TEXT - /* Warn if the image directory doesn't exist. + /* Warn if the image directory doesn't exist, when: + - not being warned before + - image directory is changed and the directory doesn't exist + - image directory does not begin with http:// */ if (p2->image_directory && *p2->image_directory && - !directory_p (p2->image_directory)) + !directory_p (p2->image_directory) && + strncmp(p2->image_directory, "http://", 6) && + ( !already_warned_about_missing_image_directory || + ( p->image_directory && + *p->image_directory && + strcmp(p->image_directory, p2->image_directory) + ) + ) + ) { char b[255]; - sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n", + sprintf (b, "Warning:\n\n" "Directory does not exist: \"%s\"\n", p2->image_directory); - warning_dialog (s->toplevel_widget, b, False, 100); + if (warning_dialog (s->toplevel_widget, b, D_NONE, 100)) + already_warned_about_missing_image_directory = True; } @@ -1431,14 +1666,19 @@ flush_dialog_changes_and_save (state *s) COPY(lock_p, "lock_p"); COPY(lock_timeout, "lock_timeout"); - COPY(dpms_enabled_p, "dpms_enabled_p"); - COPY(dpms_standby, "dpms_standby"); - COPY(dpms_suspend, "dpms_suspend"); - COPY(dpms_off, "dpms_off"); + COPY(dpms_enabled_p, "dpms_enabled_p"); + COPY(dpms_quickoff_p, "dpms_quickoff_enabled_p"); + COPY(dpms_standby, "dpms_standby"); + 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"); @@ -1451,19 +1691,26 @@ flush_dialog_changes_and_save (state *s) # 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); @@ -1471,7 +1718,7 @@ flush_dialog_changes_and_save (state *s) { Display *dpy = GDK_DISPLAY(); Bool enabled_p = (p->dpms_enabled_p && p->mode != DONT_BLANK); - sync_server_dpms_settings (dpy, enabled_p, + sync_server_dpms_settings (dpy, enabled_p, p->dpms_quickoff_p, p->dpms_standby / 1000, p->dpms_suspend / 1000, p->dpms_off / 1000, @@ -1583,7 +1830,7 @@ pref_changed_event_cb (GtkWidget *widget, GdkEvent *event, gpointer 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; @@ -1591,7 +1838,8 @@ mode_menu_item_cb (GtkWidget *widget, gpointer user_data) GtkWidget *list = name_to_widget (s, "list"); int list_elt; - GList *menu_items = gtk_container_children (GTK_CONTAINER (widget->parent)); + GList *menu_items = + gtk_container_children (GTK_CONTAINER (GET_PARENT (widget))); int menu_index = 0; saver_mode new_mode; @@ -1652,7 +1900,7 @@ list_activated_cb (GtkTreeView *list, char *str; int list_elt; - STFU g_return_if_fail (!gdk_pointer_is_grabbed ()); + g_return_if_fail (!gdk_pointer_is_grabbed ()); str = gtk_tree_path_to_string (path); list_elt = strtol (str, NULL, 10); @@ -1684,6 +1932,11 @@ list_select_changed_cb (GtkTreeSelection *selection, gpointer data) 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 */ @@ -1799,7 +2052,7 @@ list_checkbox_cb ( /* remember previous scroll position of the top of the list */ adj = gtk_scrolled_window_get_vadjustment (scroller); - scroll_top = adj->value; + scroll_top = GET_ADJ_VALUE (adj); flush_dialog_changes_and_save (s); force_list_select_item (s, GTK_WIDGET (list), list_elt, False); @@ -1831,11 +2084,12 @@ store_image_directory (GtkWidget *button, gpointer user_data) if (p->image_directory && !strcmp(p->image_directory, path)) return; /* no change */ - if (!directory_p (path)) + /* No warning for URLs. */ + if ((!directory_p (path)) && strncmp(path, "http://", 6)) { char b[255]; sprintf (b, _("Error:\n\n" "Directory does not exist: \"%s\"\n"), path); - warning_dialog (GTK_WIDGET (top), b, False, 100); + warning_dialog (GTK_WIDGET (top), b, D_NONE, 100); return; } @@ -1848,6 +2102,69 @@ store_image_directory (GtkWidget *button, gpointer user_data) } +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, D_NONE, 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, D_NONE, 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) { @@ -1862,6 +2179,20 @@ browse_image_dir_ok (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) { @@ -1905,7 +2236,78 @@ browse_image_dir_cb (GtkButton *button, gpointer user_data) } -G_MODULE_EXPORT 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... */ @@ -1921,7 +2323,7 @@ settings_sync_cmd_text (state *s) { # ifdef HAVE_XML GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text")); - char *cmd_line = get_configurator_command_line (s->cdata); + char *cmd_line = get_configurator_command_line (s->cdata, False); gtk_entry_set_text (GTK_ENTRY (cmd), cmd_line); gtk_entry_set_position (GTK_ENTRY (cmd), strlen (cmd_line)); free (cmd_line); @@ -1952,6 +2354,20 @@ settings_std_cb (GtkButton *button, gpointer user_data) gtk_notebook_set_page (notebook, 0); } +G_MODULE_EXPORT void +settings_reset_cb (GtkButton *button, gpointer user_data) +{ +# ifdef HAVE_XML + state *s = global_state_kludge; /* I hate C so much... */ + GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text")); + char *cmd_line = get_configurator_command_line (s->cdata, True); + gtk_entry_set_text (GTK_ENTRY (cmd), cmd_line); + gtk_entry_set_position (GTK_ENTRY (cmd), strlen (cmd_line)); + free (cmd_line); + populate_popup_window (s); +# endif /* HAVE_XML */ +} + G_MODULE_EXPORT void settings_switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page, gint page_num, gpointer user_data) @@ -2036,7 +2452,7 @@ server_current_hack (void) && nitems >= 3 && dataP) { - CARD32 *data = (CARD32 *) dataP; + PROP32 *data = (PROP32 *) dataP; hack_number = (int) data[2] - 1; } @@ -2046,19 +2462,39 @@ server_current_hack (void) } -/* 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) { @@ -2070,55 +2506,10 @@ scroll_to_current_hack (state *s) } -static Bool -on_path_p (const char *program) -{ - int result = False; - struct stat st; - char *cmd = strdup (program); - char *token = strchr (cmd, ' '); - char *path = 0; - int L; - - if (token) *token = 0; - token = 0; - - if (strchr (cmd, '/')) - { - result = (0 == stat (cmd, &st)); - goto DONE; - } - - path = getenv("PATH"); - if (!path || !*path) - goto DONE; - - L = strlen (cmd); - path = strdup (path); - token = strtok (path, ":"); - - while (token) - { - char *p2 = (char *) malloc (strlen (token) + L + 3); - strcpy (p2, token); - strcat (p2, "/"); - strcat (p2, cmd); - result = (0 == stat (p2, &st)); - if (result) - goto DONE; - token = strtok (0, ":"); - } - - DONE: - free (cmd); - if (path) free (path); - return result; -} - - 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")); @@ -2179,7 +2570,7 @@ populate_hack_list (state *s) pretty_name = (hack->name ? strdup (hack->name) - : make_hack_name (hack->command)); + : make_hack_name (dpy, hack->command)); if (!available_p) { @@ -2187,7 +2578,7 @@ populate_hack_list (state *s) (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; + GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (list)); GdkColor *fg = &style->fg[GTK_STATE_INSENSITIVE]; /* GdkColor *bg = &style->bg[GTK_STATE_INSENSITIVE]; */ char *buf = (char *) malloc (strlen (pretty_name) + 100); @@ -2311,8 +2702,11 @@ static void 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 @@ -2377,6 +2771,13 @@ populate_prefs_page (state *s) # 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...) @@ -2409,10 +2810,13 @@ populate_prefs_page (state *s) (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 ("dpms_quickoff_button", p->dpms_quickoff_p); TOGGLE_ACTIVE ("grab_desk_button", p->grab_desktop_p); TOGGLE_ACTIVE ("grab_video_button", p->grab_video_p); TOGGLE_ACTIVE ("grab_image_button", p->random_image_p); @@ -2420,6 +2824,15 @@ populate_prefs_page (state *s) 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")), @@ -2429,6 +2842,29 @@ populate_prefs_page (state *s) 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")); @@ -2447,7 +2883,7 @@ populate_prefs_page (state *s) 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++) { @@ -2484,8 +2920,11 @@ populate_prefs_page (state *s) /* DPMS */ +dpms_supported=1; SENSITIZE ("dpms_frame", dpms_supported); SENSITIZE ("dpms_button", dpms_supported); + SENSITIZE ("dpms_quickoff_button", dpms_supported); + SENSITIZE ("dpms_standby_label", dpms_supported && p->dpms_enabled_p); SENSITIZE ("dpms_standby_mlabel", dpms_supported && p->dpms_enabled_p); SENSITIZE ("dpms_standby_spinbutton", dpms_supported && p->dpms_enabled_p); @@ -2565,23 +3004,78 @@ populate_popup_window (state *s) 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 = GET_WINDOW (s->toplevel_widget); + 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. @@ -2644,7 +3138,7 @@ fix_text_entry_sizes (state *s) #ifdef HAVE_GTK2 PangoFontMetrics *pain = pango_context_get_metrics (gtk_widget_get_pango_context (w), - w->style->font_desc, + gtk_widget_get_style (w)->font_desc, gtk_get_default_language ()); height = PANGO_PIXELS (pango_font_metrics_get_ascent (pain) + pango_font_metrics_get_descent (pain)); @@ -2763,6 +3257,7 @@ map_prev_button_cb (GtkWidget *w, gpointer user_data) #endif /* !HAVE_GTK2 */ +#ifndef HAVE_GTK2 /* Work around a Gtk bug that causes label widgets to wrap text too early. */ @@ -2784,7 +3279,6 @@ you_are_not_a_unique_or_beautiful_snowflake (GtkWidget *label, gtk_widget_size_request (label, &req); } - /* Feel the love. Thanks to Nat Friedman for finding this workaround. */ static void @@ -2806,16 +3300,18 @@ eschew_gtk_lossage (GtkLabel *label) 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; GtkFrame *frame1 = GTK_FRAME (name_to_widget (s, "preview_frame")); - GtkFrame *frame2 = GTK_FRAME (name_to_widget (s, "doc_frame")); + GtkFrame *frame2 = GTK_FRAME (name_to_widget (s, "opt_frame")); GtkEntry *cmd = GTK_ENTRY (name_to_widget (s, "cmd_text")); GtkCombo *vis = GTK_COMBO (name_to_widget (s, "visual_combo")); GtkWidget *list = GTK_WIDGET (name_to_widget (s, "list")); @@ -2842,7 +3338,7 @@ populate_demo_window (state *s, int list_elt) pretty_name = (hack ? (hack->name ? strdup (hack->name) - : make_hack_name (hack->command)) + : make_hack_name (dpy, hack->command)) : 0); if (hack) @@ -2923,6 +3419,7 @@ sort_hack_cmp (const void *a, const void *b) static void initialize_sort_map (state *s) { + Display *dpy = GDK_DISPLAY(); saver_preferences *p = &s->prefs; int i, j; @@ -2936,13 +3433,16 @@ initialize_sort_map (state *s) calloc (sizeof(int), p->screenhacks_count + 1); s->hacks_available_p = (Bool *) calloc (sizeof(Bool), p->screenhacks_count + 1); + s->total_available = 0; /* Check which hacks actually exist on $PATH */ for (i = 0; i < p->screenhacks_count; i++) { screenhack *hack = p->screenhacks[i]; - s->hacks_available_p[i] = on_path_p (hack->command); + int on = on_path_p (hack->command) ? 1 : 0; + s->hacks_available_p[i] = on; + s->total_available += on; } /* Initialize list->hack table to unsorted mapping, omitting nonexistent @@ -2970,7 +3470,7 @@ initialize_sort_map (state *s) 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); @@ -2993,13 +3493,18 @@ initialize_sort_map (state *s) /* 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; @@ -3020,10 +3525,10 @@ maybe_reload_init_file (state *s) _("Warning:\n\n" "file \"%s\" has changed, reloading.\n"), f); - warning_dialog (s->toplevel_widget, b, False, 100); + warning_dialog (s->toplevel_widget, b, D_NONE, 100); free (b); - load_init_file (p); + load_init_file (dpy, p); initialize_sort_map (s); list_elt = selected_list_element (s); @@ -3070,16 +3575,18 @@ clear_preview_window (state *s) { GtkWidget *p; GdkWindow *window; + GtkStyle *style; if (!s->toplevel_widget) return; /* very early */ p = name_to_widget (s, "preview"); - window = p->window; + window = GET_WINDOW (p); if (!window) return; /* Flush the widget background down into the window, in case a subproc has changed it. */ - gdk_window_set_background (window, &p->style->bg[GTK_STATE_NORMAL]); + style = gtk_widget_get_style (p); + gdk_window_set_background (window, &style->bg[GTK_STATE_NORMAL]); gdk_window_clear (window); { @@ -3090,11 +3597,14 @@ clear_preview_window (state *s) Bool available_p = (hack_number >= 0 ? s->hacks_available_p [hack_number] : True); + Bool nothing_p = (s->total_available < 5); + #ifdef HAVE_GTK2 GtkWidget *notebook = name_to_widget (s, "preview_notebook"); gtk_notebook_set_page (GTK_NOTEBOOK (notebook), (s->running_preview_error_p - ? (available_p ? 1 : 2) + ? (available_p ? 1 : + nothing_p ? 3 : 2) : 0)); #else /* !HAVE_GTK2 */ if (s->running_preview_error_p) @@ -3137,15 +3647,16 @@ reset_preview_window (state *s) when changing hacks, instead of always trying to reuse the same one? */ GtkWidget *pr = name_to_widget (s, "preview"); - if (GTK_WIDGET_REALIZED (pr)) + if (GET_REALIZED (pr)) { - Window oid = (pr->window ? GDK_WINDOW_XWINDOW (pr->window) : 0); + GdkWindow *window = GET_WINDOW (pr); + Window oid = (window ? GDK_WINDOW_XWINDOW (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); + id = (window ? GDK_WINDOW_XWINDOW (window) : 0); if (s->debug_p) fprintf (stderr, "%s: window id 0x%X -> 0x%X\n", blurb(), (unsigned int) oid, @@ -3170,7 +3681,7 @@ fix_preview_visual (state *s) (visual == dvisual ? "default" : "non-default"), (xvisual ? (unsigned long) xvisual->visualid : 0L)); - if (!GTK_WIDGET_REALIZED (widget) || + if (!GET_REALIZED (widget) || gtk_widget_get_visual (widget) != visual) { gtk_widget_unrealize (widget); @@ -3181,8 +3692,8 @@ fix_preview_visual (state *s) /* Set the Widget colors to be white-on-black. */ { - GdkWindow *window = widget->window; - GtkStyle *style = gtk_style_copy (widget->style); + GdkWindow *window = GET_WINDOW (widget); + GtkStyle *style = gtk_style_copy (gtk_widget_get_style (widget)); GdkColormap *cmap = gtk_widget_get_colormap (widget); GdkColor *fg = &style->fg[GTK_STATE_NORMAL]; GdkColor *bg = &style->bg[GTK_STATE_NORMAL]; @@ -3335,7 +3846,8 @@ get_best_gl_visual (state *s) 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. */ @@ -3403,9 +3915,13 @@ kill_preview_subproc (state *s, Bool reset_p) perror (buf); } } - else if (s->debug_p) - fprintf (stderr, "%s: killed pid %lu (%s)\n", blurb(), - (unsigned long) 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; @@ -3440,7 +3956,7 @@ launch_preview_subproc (state *s) reset_preview_window (s); - window = pr->window; + window = GET_WINDOW (pr); s->running_preview_error_p = False; @@ -3622,6 +4138,13 @@ update_subproc_timer (gpointer data) return FALSE; /* do not re-execute timer */ } +static int +settings_timer (gpointer data) +{ + settings_cb (0, 0); + return FALSE; +} + /* Call this when you think you might want a preview process running. It will set a timer that will actually launch that program a second @@ -3778,6 +4301,29 @@ check_blanked_timer (gpointer data) 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; +} + /* Setting window manager icon */ @@ -3786,9 +4332,8 @@ static void init_icon (GdkWindow *window) { GdkBitmap *mask = 0; - GdkColor transp; GdkPixmap *pixmap = - gdk_pixmap_create_from_xpm_d (window, &mask, &transp, + gdk_pixmap_create_from_xpm_d (window, &mask, 0, (gchar **) logo_50_xpm); if (pixmap) gdk_window_set_icon (window, 0, pixmap, mask); @@ -3822,6 +4367,77 @@ mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, #endif +static Window +gnome_screensaver_window (Screen *screen) +{ + Display *dpy = DisplayOfScreen (screen); + Window root = RootWindowOfScreen (screen); + Window parent, *kids; + unsigned int nkids; + Window gnome_window = 0; + int i; + + if (! XQueryTree (dpy, root, &root, &parent, &kids, &nkids)) + abort (); + for (i = 0; i < nkids; i++) + { + Atom type; + int format; + unsigned long nitems, bytesafter; + unsigned char *name; + if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128, + False, XA_STRING, &type, &format, &nitems, + &bytesafter, &name) + == Success + && type != None + && !strcmp ((char *) name, "gnome-screensaver")) + { + gnome_window = kids[i]; + break; + } + } + + if (kids) XFree ((char *) kids); + return gnome_window; +} + +static Bool +gnome_screensaver_active_p (void) +{ + Display *dpy = GDK_DISPLAY(); + Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy)); + return (w ? True : False); +} + +static void +kill_gnome_screensaver (void) +{ + Display *dpy = GDK_DISPLAY(); + Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy)); + if (w) XKillClient (dpy, (XID) w); +} + +static Bool +kde_screensaver_active_p (void) +{ + FILE *p = popen ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null", + "r"); + char buf[255]; + fgets (buf, sizeof(buf)-1, p); + pclose (p); + if (!strcmp (buf, "true\n")) + return True; + else + return False; +} + +static void +kill_kde_screensaver (void) +{ + system ("dcop kdesktop KScreensaverIface enable false"); +} + + static void the_network_is_not_the_computer (state *s) { @@ -3935,12 +4551,36 @@ the_network_is_not_the_computer (state *s) if (*msg) - warning_dialog (s->toplevel_widget, msg, True, 1); + warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1); if (rversion) free (rversion); if (ruser) free (ruser); if (rhost) free (rhost); free (msg); + msg = 0; + + /* Note: since these dialogs are not modal, they will stack up. + So we do this check *after* popping up the "xscreensaver is not + running" dialog so that these are on top. Good enough. + */ + + if (gnome_screensaver_active_p ()) + warning_dialog (s->toplevel_widget, + _("Warning:\n\n" + "The GNOME screensaver daemon appears to be running.\n" + "It must be stopped for XScreenSaver to work properly.\n" + "\n" + "Stop the GNOME screen saver daemon now?\n"), + D_GNOME, 1); + + if (kde_screensaver_active_p ()) + warning_dialog (s->toplevel_widget, + _("Warning:\n\n" + "The KDE screen saver daemon appears to be running.\n" + "It must be stopped for XScreenSaver to work properly.\n" + "\n" + "Stop the KDE screen saver daemon now?\n"), + D_KDE, 1); } @@ -3996,6 +4636,7 @@ g_log_handler (const gchar *log_domain, GLogLevelFlags log_level, the .ad file... */ #endif +STFU static char *defaults[] = { #include "XScreenSaver_ad.h" 0 @@ -4009,7 +4650,7 @@ static struct poptOption crapplet_options[] = { #endif /* HAVE_CRAPPLET */ #endif /* 0 */ -const char *usage = "[--display dpy] [--prefs]" +const char *usage = "[--display dpy] [--prefs | --settings]" # ifdef HAVE_CRAPPLET " [--crapplet]" # endif @@ -4020,9 +4661,13 @@ 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; } @@ -4071,7 +4716,7 @@ delayed_scroll_kludge (gpointer data) #ifdef HAVE_GTK2 -GtkWidget * +static GtkWidget * create_xscreensaver_demo (void) { GtkWidget *nb; @@ -4082,7 +4727,7 @@ create_xscreensaver_demo (void) return name_to_widget (global_state_kludge, "xscreensaver_demo"); } -GtkWidget * +static GtkWidget * create_xscreensaver_settings_dialog (void) { GtkWidget *w, *box; @@ -4106,7 +4751,8 @@ main (int argc, char **argv) XtAppContext app; state S, *s; saver_preferences *p; - Bool prefs = False; + Bool prefs_p = False; + Bool settings_p = False; int i; Display *dpy; Widget toplevel_shell; @@ -4372,7 +5018,9 @@ main (int argc, char **argv) if (str[0] == '-' && str[1] == '-') str++; if (!strcmp (str, "-prefs")) - prefs = True; + prefs_p = True; + else if (!strcmp (str, "-settings")) + settings_p = 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. */ @@ -4392,10 +5040,11 @@ main (int argc, char **argv) was in argv[0]. */ p->db = db; + s->nscreens = screen_count (dpy); hack_environment (s); /* must be before initialize_sort_map() */ - load_init_file (p); + load_init_file (dpy, p); initialize_sort_map (s); /* Now that Xt has been initialized, and the resources have been read, @@ -4477,6 +5126,8 @@ main (int argc, char **argv) gtk_widget_set_sensitive (std, False); std = GTK_WIDGET (name_to_widget (s, "adv_button")); gtk_widget_hide (std); + std = GTK_WIDGET (name_to_widget (s, "reset_button")); + gtk_widget_hide (std); page = 1; # endif /* !HAVE_XML */ @@ -4517,15 +5168,31 @@ main (int argc, char **argv) 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)); + } } /* Handle the -prefs command-line argument. */ - if (prefs) + if (prefs_p) { GtkNotebook *notebook = GTK_NOTEBOOK (name_to_widget (s, "notebook")); @@ -4563,7 +5230,7 @@ main (int argc, char **argv) { GtkWidget *window = capplet; while (window && !GTK_IS_WINDOW (window)) - window = window->parent; + window = GET_PARENT (window); if (window) { gtk_window_set_title (GTK_WINDOW (window), window_title); @@ -4598,7 +5265,7 @@ main (int argc, char **argv) #endif gtk_widget_show (s->toplevel_widget); - init_icon (GTK_WIDGET (s->toplevel_widget)->window); /* after `show' */ + init_icon (GET_WINDOW (GTK_WIDGET (s->toplevel_widget))); /* after `show' */ fix_preview_visual (s); /* Realize page zero, so that we can diddle the scrollbar when the @@ -4615,8 +5282,28 @@ main (int argc, char **argv) gtk_timeout_add (60 * 1000, check_blanked_timer, s); + /* Handle the --settings command-line argument. */ + if (settings_p) + gtk_timeout_add (500, settings_timer, 0); + + /* 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); + + + if (decrepit_p()) + warning_dialog (s->toplevel_widget, + _("Warning:\n\n" + "This version of xscreensaver is VERY OLD!\n" + "Please upgrade!\n" + "\n" + "https://www.jwz.org/xscreensaver/\n" + "\n" + "(If this is the latest version that your distro ships, then\n" + "your distro is doing you a disservice. Build from source.)\n" + ), + D_NONE, 7); /* Run the Gtk event loop, and not the Xt event loop. This means that @@ -4634,17 +5321,18 @@ main (int argc, char **argv) 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[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