X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=driver%2Fdemo-Gtk.c;h=298860a7e130a07dfb0cd4f4c0a9cd5435e8b27c;hp=dc6f46551d0e898c2ce1a003ae71b538d22d92f9;hb=ffd8c0873576a9e3065696a624dce6b766b77062;hpb=cccbddbc4140cf9a06d7d95cc5c0ca36eb5d6e28 diff --git a/driver/demo-Gtk.c b/driver/demo-Gtk.c index dc6f4655..298860a7 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-2002 Jamie Zawinski + * xscreensaver, Copyright (c) 1993-2004 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 @@ -16,12 +16,25 @@ #ifdef HAVE_GTK /* whole file */ +#include + #include #ifdef HAVE_UNISTD_H # include #endif +# ifdef __GNUC__ +# define STFU __extension__ /* ignore gcc -pendantic warnings in next sexp */ +# else +# define STFU /* */ +# endif + + +#ifdef ENABLE_NLS +# include +#endif /* ENABLE_NLS */ + #ifndef VMS # include /* for getpwuid() */ #else /* VMS */ @@ -74,6 +87,25 @@ #include +#ifdef HAVE_GTK2 +#include +#endif /* HAVE_GTK2 */ + +#if defined(DEFAULT_ICONDIR) && !defined(GLADE_DIR) +# define GLADE_DIR DEFAULT_ICONDIR +#endif +#if !defined(DEFAULT_ICONDIR) && defined(GLADE_DIR) +# 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 "resources.h" /* for parse_time() */ @@ -84,6 +116,9 @@ #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" @@ -92,10 +127,19 @@ #include #include +#ifdef HAVE_GTK2 +enum { + COL_ENABLED, + COL_NAME, + COL_LAST +}; +#endif /* HAVE_GTK2 */ /* from exec.c */ extern void exec_command (const char *shell, const char *command, int nice); +static void hack_subproc_environment (Window preview_window_id, Bool debug_p); + #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) @@ -118,6 +162,10 @@ typedef struct { GtkWidget *popup_widget; /* the "Settings" dialog */ conf_data *cdata; /* private data for per-hack configuration */ +#ifdef HAVE_GTK2 + GladeXML *glade_ui; /* Glade UI file */ +#endif /* HAVE_GTK2 */ + Bool debug_p; /* whether to print diagnostics */ Bool initializing_p; /* flag for breaking recursion loops */ Bool saving_p; /* flag for breaking recursion loops */ @@ -134,6 +182,10 @@ 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 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 */ @@ -164,7 +216,7 @@ static int maybe_reload_init_file (state *); static void await_xscreensaver (state *); 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 *); @@ -197,11 +249,48 @@ name_to_widget (state *s, const char *name) if (!name) abort(); if (!*name) abort(); +#ifdef HAVE_GTK2 + if (!s->glade_ui) + { + /* 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_NAME "\"\n" + "\tfrom " GLADE_DIR "/ or current directory.\n", + blurb()); + exit (-1); + } +# undef GLADE_FILE_NAME + + glade_xml_signal_autoconnect (s->glade_ui); + } + + w = glade_xml_get_widget (s->glade_ui, name); + +#else /* !HAVE_GTK2 */ + w = (GtkWidget *) gtk_object_get_data (GTK_OBJECT (s->base_widget), name); if (w) return w; w = (GtkWidget *) gtk_object_get_data (GTK_OBJECT (s->popup_widget), name); +#endif /* HAVE_GTK2 */ if (w) return w; fprintf (stderr, "%s: no widget \"%s\"\n", blurb(), name); @@ -215,6 +304,24 @@ name_to_widget (state *s, const char *name) static void ensure_selected_item_visible (GtkWidget *widget) { +#ifdef HAVE_GTK2 + GtkTreePath *path; + GtkTreeSelection *selection; + GtkTreeIter iter; + GtkTreeModel *model; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + path = gtk_tree_path_new_first (); + else + path = gtk_tree_model_get_path (model, &iter); + + gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE); + + gtk_tree_path_free (path); + +#else /* !HAVE_GTK2 */ + GtkScrolledWindow *scroller = 0; GtkViewport *vp = 0; GtkList *list_widget = 0; @@ -299,6 +406,7 @@ ensure_selected_item_visible (GtkWidget *widget) gtk_adjustment_set_value (adj, target); } +#endif /* !HAVE_GTK2 */ } static void @@ -335,7 +443,8 @@ warning_dialog (GtkWidget *parent, const char *message, 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; @@ -352,7 +461,11 @@ warning_dialog (GtkWidget *parent, const char *message, { label = gtk_label_new (head); +#ifdef HAVE_GTK2 + gtk_label_set_selectable (GTK_LABEL (label), TRUE); +#endif /* HAVE_GTK2 */ +#ifndef HAVE_GTK2 if (i == 1) { GTK_WIDGET (label)->style = @@ -363,7 +476,7 @@ warning_dialog (GtkWidget *parent, const char *message, gtk_widget_set_style (GTK_WIDGET (label), GTK_WIDGET (label)->style); } - +#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), @@ -388,6 +501,18 @@ warning_dialog (GtkWidget *parent, const char *message, gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), label, TRUE, TRUE, 0); +#ifdef HAVE_GTK2 + if (restart_button_p) + { + cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + gtk_container_add (GTK_CONTAINER (label), cancel); + } + + ok = gtk_button_new_from_stock (GTK_STOCK_OK); + gtk_container_add (GTK_CONTAINER (label), ok); + +#else /* !HAVE_GTK2 */ + ok = gtk_button_new_with_label ("OK"); gtk_container_add (GTK_CONTAINER (label), ok); @@ -397,15 +522,22 @@ warning_dialog (GtkWidget *parent, const char *message, gtk_container_add (GTK_CONTAINER (label), cancel); } +#endif /* !HAVE_GTK2 */ + 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); gtk_widget_show (ok); + gtk_widget_grab_focus (ok); + if (cancel) - gtk_widget_show (cancel); + { + STFU GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT); + gtk_widget_show (cancel); + } gtk_widget_show (label); gtk_widget_show (dialog); -/* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/ if (restart_button_p) { @@ -426,8 +558,12 @@ warning_dialog (GtkWidget *parent, const char *message, gdk_window_set_transient_for (GTK_WIDGET (dialog)->window, GTK_WIDGET (parent)->window); +#ifdef HAVE_GTK2 + gtk_window_present (GTK_WINDOW (dialog)); +#else /* !HAVE_GTK2 */ gdk_window_show (GTK_WIDGET (dialog)->window); gdk_window_raise (GTK_WIDGET (dialog)->window); +#endif /* !HAVE_GTK2 */ free (msg); } @@ -441,6 +577,11 @@ run_cmd (state *s, Atom command, int arg) 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]; @@ -484,16 +625,17 @@ 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; } @@ -504,13 +646,22 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data) char *vers = strdup (screensaver_id + 4); char *s; char copy[1024]; - char *desc = "For updates, check http://www.jwz.org/xscreensaver/"; + char *desc = _("For updates, check http://www.jwz.org/xscreensaver/"); s = strchr (vers, ','); *s = 0; s += 2; - sprintf(copy, "Copyright \251 1991-2002 %s", s); + /* 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-2004 %s"), s); +#else /* !HAVE_GTK2 */ + sprintf(copy, ("Copyright \251 1991-2004 %s"), s); +#endif /* !HAVE_GTK2 */ sprintf (msg, "%s\n\n%s", copy, desc); @@ -560,27 +711,35 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data) gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (label1), 0.0, 0.75); +#ifndef HAVE_GTK2 GTK_WIDGET (label1)->style = gtk_style_copy (GTK_WIDGET (label1)->style); GTK_WIDGET (label1)->style->font = gdk_font_load (get_string_resource ("about.headingFont","Dialog.Font")); gtk_widget_set_style (GTK_WIDGET (label1), GTK_WIDGET (label1)->style); +#endif /* HAVE_GTK2 */ label2 = gtk_label_new (msg); gtk_box_pack_start (GTK_BOX (vbox), label2, TRUE, TRUE, 0); gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (label2), 0.0, 0.25); +#ifndef HAVE_GTK2 GTK_WIDGET (label2)->style = gtk_style_copy (GTK_WIDGET (label2)->style); GTK_WIDGET (label2)->style->font = gdk_font_load (get_string_resource ("about.bodyFont","Dialog.Font")); gtk_widget_set_style (GTK_WIDGET (label2), GTK_WIDGET (label2)->style); +#endif /* HAVE_GTK2 */ hb = gtk_hbutton_box_new (); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), hb, TRUE, TRUE, 0); - ok = gtk_button_new_with_label ("OK"); +#ifdef HAVE_GTK2 + ok = gtk_button_new_from_stock (GTK_STOCK_OK); +#else /* !HAVE_GTK2 */ + ok = gtk_button_new_with_label (_("OK")); +#endif /* !HAVE_GTK2 */ gtk_container_add (GTK_CONTAINER (hb), ok); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); @@ -617,8 +776,8 @@ doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data) if (!p->help_url || !*p->help_url) { warning_dialog (s->toplevel_widget, - "Error:\n\n" - "No Help URL has been specified.\n", False, 100); + _("Error:\n\n" + "No Help URL has been specified.\n"), False, 100); return; } @@ -703,13 +862,19 @@ await_xscreensaver (state *s) Bool root_p = (geteuid () == 0); strcpy (buf, - "Error:\n\n" - "The xscreensaver daemon did not start up properly.\n" - "\n"); + _("Error:\n\n" + "The xscreensaver daemon did not start up properly.\n" + "\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" + _("You are running as root. This usually means that xscreensaver\n" "was unable to contact your X server because access control is\n" "turned on. Try running this command:\n" "\n" @@ -723,9 +888,9 @@ await_xscreensaver (state *s) "manual and FAQ for more information.\n" "\n" "You shouldn't run X as root. Instead, you should log in as a\n" - "normal user, and `su' as necessary."); + "normal user, and `su' as necessary.")); else - strcat (buf, "Please check your $PATH and permissions."); + strcat (buf, _("Please check your $PATH and permissions.")); warning_dialog (s->toplevel_widget, buf, False, 1); } @@ -760,12 +925,12 @@ demo_write_init_file (state *s, saver_preferences *p) const char *f = init_file_name(); if (!f || !*f) warning_dialog (s->toplevel_widget, - "Error:\n\nCouldn't determine init file name!\n", + _("Error:\n\nCouldn't determine init file name!\n"), False, 100); else { char *b = (char *) malloc (strlen(f) + 1024); - sprintf (b, "Error:\n\nCouldn't write %s\n", f); + sprintf (b, _("Error:\n\nCouldn't write %s\n"), f); warning_dialog (s->toplevel_widget, b, False, 100); free (b); } @@ -790,7 +955,7 @@ manual_cb (GtkButton *button, gpointer user_data) { 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; @@ -798,7 +963,7 @@ manual_cb (GtkButton *button, gpointer user_data) 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; @@ -824,7 +989,7 @@ manual_cb (GtkButton *button, gpointer user_data) else { warning_dialog (GTK_WIDGET (button), - "Error:\n\nno `manualCommand' resource set.", + _("Error:\n\nno `manualCommand' resource set."), False, 100); } @@ -833,13 +998,26 @@ manual_cb (GtkButton *button, gpointer user_data) static void -force_list_select_item (state *s, GtkList *list, int list_elt, Bool scroll_p) +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); +#ifdef HAVE_GTK2 + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *selection; +#endif /* HAVE_GTK2 */ 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); +#else /* !HAVE_GTK2 */ gtk_list_select_item (GTK_LIST (list), list_elt); +#endif /* !HAVE_GTK2 */ if (scroll_p) ensure_selected_item_visible (GTK_WIDGET (list)); if (!was) gtk_widget_set_sensitive (parent, False); } @@ -849,11 +1027,10 @@ 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; - 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); if (list_elt < 0) @@ -861,13 +1038,13 @@ run_next_cb (GtkButton *button, gpointer user_data) else list_elt++; - if (list_elt >= p->screenhacks_count) + if (list_elt >= s->list_count) list_elt = 0; s->preview_suppressed_p = True; flush_dialog_changes_and_save (s); - force_list_select_item (s, GTK_LIST (list_widget), list_elt, True); + force_list_select_item (s, list_widget, list_elt, True); populate_demo_window (s, list_elt); run_hack (s, list_elt, False); @@ -879,25 +1056,24 @@ 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; - 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); 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; flush_dialog_changes_and_save (s); - force_list_select_item (s, GTK_LIST (list_widget), list_elt, True); + force_list_select_item (s, list_widget, list_elt, True); populate_demo_window (s, list_elt); run_hack (s, list_elt, False); @@ -920,7 +1096,7 @@ flush_changes (state *s, 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]; @@ -983,7 +1159,7 @@ hack_time_text (state *s, const char *line, Time *store, Bool sec_p) 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; @@ -994,8 +1170,8 @@ hack_time_text (state *s, const char *line, Time *store, Bool sec_p) { char b[255]; sprintf (b, - "Error:\n\n" - "Unparsable time format: \"%s\"\n", + _("Error:\n\n" + "Unparsable time format: \"%s\"\n"), line); warning_dialog (s->toplevel_widget, b, False, 100); } @@ -1024,8 +1200,8 @@ 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 */ @@ -1067,6 +1243,39 @@ normalize_directory (const char *path) } +#ifdef HAVE_GTK2 + +typedef struct { + state *s; + int i; + Bool *changed; +} FlushForeachClosure; + +static gboolean +flush_checkbox (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + FlushForeachClosure *closure = data; + gboolean checked; + + gtk_tree_model_get (model, iter, + COL_ENABLED, &checked, + -1); + + if (flush_changes (closure->s, closure->i, + checked, 0, 0)) + *closure->changed = True; + + closure->i++; + + /* don't remove row */ + return FALSE; +} + +#endif /* HAVE_GTK2 */ + /* Flush out any changes made in the main dialog window (where changes take place immediately: clicking on a checkbox causes the init file to be written right away.) @@ -1076,11 +1285,18 @@ flush_dialog_changes_and_save (state *s) { saver_preferences *p = &s->prefs; saver_preferences P2, *p2 = &P2; +#ifdef HAVE_GTK2 + GtkTreeView *list_widget = GTK_TREE_VIEW (name_to_widget (s, "list")); + GtkTreeModel *model = gtk_tree_view_get_model (list_widget); + FlushForeachClosure closure; +#else /* !HAVE_GTK2 */ GtkList *list_widget = GTK_LIST (name_to_widget (s, "list")); GList *kids = gtk_container_children (GTK_CONTAINER (list_widget)); + int i; +#endif /* !HAVE_GTK2 */ + Bool changed = False; GtkWidget *w; - int i; if (s->saving_p) return False; s->saving_p = True; @@ -1089,6 +1305,14 @@ flush_dialog_changes_and_save (state *s) /* Flush any checkbox changes in the list down into the prefs struct. */ +#ifdef HAVE_GTK2 + closure.s = s; + closure.changed = &changed; + closure.i = 0; + gtk_tree_model_foreach (model, flush_checkbox, &closure); + +#else /* !HAVE_GTK2 */ + for (i = 0; kids; kids = kids->next, i++) { GtkWidget *line = GTK_WIDGET (kids->data); @@ -1101,7 +1325,7 @@ flush_dialog_changes_and_save (state *s) if (flush_changes (s, i, (checked ? 1 : 0), 0, 0)) changed = True; } - +#endif /* ~HAVE_GTK2 */ /* Flush the non-hack-specific settings down into the prefs struct. */ @@ -1187,7 +1411,7 @@ flush_dialog_changes_and_save (state *s) 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 @@ -1305,13 +1529,13 @@ flush_popup_changes_and_save (state *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 { gdk_beep (); /* unparsable */ visual = ""; - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any"); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), _("Any")); } changed = flush_changes (s, list_elt, -1, command, visual); @@ -1330,8 +1554,6 @@ flush_popup_changes_and_save (state *s) } - - void pref_changed_cb (GtkWidget *widget, gpointer user_data) { @@ -1344,6 +1566,12 @@ pref_changed_cb (GtkWidget *widget, gpointer user_data) } } +gboolean +pref_changed_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + pref_changed_cb (widget, user_data); + return FALSE; +} /* Callback on menu items in the "mode" options menu. */ @@ -1352,13 +1580,12 @@ mode_menu_item_cb (GtkWidget *widget, gpointer user_data) { state *s = (state *) user_data; saver_preferences *p = &s->prefs; - GtkList *list = GTK_LIST (name_to_widget (s, "list")); + GtkWidget *list = name_to_widget (s, "list"); int list_elt; GList *menu_items = gtk_container_children (GTK_CONTAINER (widget->parent)); int menu_index = 0; saver_mode new_mode; - int old_selected = p->selected_hack; while (menu_items) { @@ -1372,17 +1599,12 @@ mode_menu_item_cb (GtkWidget *widget, gpointer user_data) 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; @@ -1393,9 +1615,6 @@ mode_menu_item_cb (GtkWidget *widget, gpointer user_data) } pref_changed_cb (widget, user_data); - - if (old_selected != p->selected_hack) - abort(); /* dammit, not again... */ } @@ -1414,6 +1633,52 @@ switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page, schedule_preview (s, 0); } +#ifdef HAVE_GTK2 +static void +list_activated_cb (GtkTreeView *list, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer data) +{ + state *s = data; + char *str; + int list_elt; + + STFU g_return_if_fail (!gdk_pointer_is_grabbed ()); + + str = gtk_tree_path_to_string (path); + list_elt = strtol (str, NULL, 10); + g_free (str); + + if (list_elt >= 0) + run_hack (s, list_elt, True); +} + +static void +list_select_changed_cb (GtkTreeSelection *selection, gpointer data) +{ + state *s = (state *)data; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreePath *path; + char *str; + int list_elt; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + path = gtk_tree_model_get_path (model, &iter); + str = gtk_tree_path_to_string (path); + list_elt = strtol (str, NULL, 10); + + gtk_tree_path_free (path); + g_free (str); + + populate_demo_window (s, list_elt); + flush_dialog_changes_and_save (s); +} + +#else /* !HAVE_GTK2 */ static time_t last_doubleclick_time = 0; /* FMH! This is to suppress the list_select_cb that comes in @@ -1462,6 +1727,8 @@ list_unselect_cb (GtkList *list, GtkWidget *child, gpointer data) flush_dialog_changes_and_save (s); } +#endif /* !HAVE_GTK2 */ + /* Called when the checkboxes that are in the left column of the scrolling list are clicked. This both populates the right pane @@ -1469,27 +1736,65 @@ list_unselect_cb (GtkList *list, GtkWidget *child, gpointer data) also syncs this checkbox with the right pane Enabled checkbox. */ static void -list_checkbox_cb (GtkWidget *cb, gpointer data) +list_checkbox_cb ( +#ifdef HAVE_GTK2 + GtkCellRendererToggle *toggle, + gchar *path_string, +#else /* !HAVE_GTK2 */ + GtkWidget *cb, +#endif /* !HAVE_GTK2 */ + gpointer data) { state *s = (state *) data; +#ifdef HAVE_GTK2 + GtkScrolledWindow *scroller = + GTK_SCROLLED_WINDOW (name_to_widget (s, "scroller")); + GtkTreeView *list = GTK_TREE_VIEW (name_to_widget (s, "list")); + GtkTreeModel *model = gtk_tree_view_get_model (list); + GtkTreePath *path = gtk_tree_path_new_from_string (path_string); + GtkTreeIter iter; + gboolean active; +#else /* !HAVE_GTK2 */ GtkWidget *line_hbox = GTK_WIDGET (cb)->parent; GtkWidget *line = GTK_WIDGET (line_hbox)->parent; GtkList *list = GTK_LIST (GTK_WIDGET (line)->parent); GtkViewport *vp = GTK_VIEWPORT (GTK_WIDGET (list)->parent); GtkScrolledWindow *scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent); +#endif /* !HAVE_GTK2 */ GtkAdjustment *adj; double scroll_top; - int list_elt = gtk_list_child_position (list, line); + int list_elt; + +#ifdef HAVE_GTK2 + if (!gtk_tree_model_get_iter (model, &iter, path)) + { + g_warning ("bad path: %s", path_string); + return; + } + gtk_tree_path_free (path); + + gtk_tree_model_get (model, &iter, + COL_ENABLED, &active, + -1); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + COL_ENABLED, !active, + -1); + + list_elt = strtol (path_string, NULL, 10); +#else /* !HAVE_GTK2 */ + list_elt = gtk_list_child_position (list, line); +#endif /* !HAVE_GTK2 */ /* remember previous scroll position of the top of the list */ adj = gtk_scrolled_window_get_vadjustment (scroller); scroll_top = adj->value; flush_dialog_changes_and_save (s); - force_list_select_item (s, list, list_elt, False); + force_list_select_item (s, GTK_WIDGET (list), list_elt, False); populate_demo_window (s, list_elt); /* restore the previous scroll position of the top of the list. @@ -1513,7 +1818,7 @@ store_image_directory (GtkWidget *button, gpointer user_data) GtkFileSelection *selector = fsd->widget; GtkWidget *top = s->toplevel_widget; saver_preferences *p = &s->prefs; - char *path = gtk_file_selection_get_filename (selector); + const char *path = gtk_file_selection_get_filename (selector); if (p->image_directory && !strcmp(p->image_directory, path)) return; /* no change */ @@ -1521,7 +1826,7 @@ store_image_directory (GtkWidget *button, gpointer user_data) if (!directory_p (path)) { char b[255]; - sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n", path); + sprintf (b, _("Error:\n\n" "Directory does not exist: \"%s\"\n"), path); warning_dialog (GTK_WIDGET (top), b, False, 100); return; } @@ -1687,11 +1992,12 @@ settings_ok_cb (GtkButton *button, gpointer user_data) 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; } @@ -1708,7 +2014,7 @@ server_current_hack (void) Atom type; int format; unsigned long nitems, bytesafter; - CARD32 *data = 0; + unsigned char *dataP = 0; Display *dpy = GDK_DISPLAY(); int hack_number = -1; @@ -1716,14 +2022,17 @@ server_current_hack (void) 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) + { + CARD32 *data = (CARD32 *) dataP; + hack_number = (int) data[2] - 1; + } - if (data) free (data); + if (dataP) XFree (dataP); return hack_number; } @@ -1746,22 +2055,162 @@ scroll_to_current_hack (state *s) if (hack_number >= 0 && hack_number < p->screenhacks_count) { int list_elt = s->hack_number_to_list_elt[hack_number]; - GtkList *list = GTK_LIST (name_to_widget (s, "list")); + GtkWidget *list = name_to_widget (s, "list"); force_list_select_item (s, list, list_elt, True); populate_demo_window (s, list_elt); } } +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) { +#ifdef HAVE_GTK2 + saver_preferences *p = &s->prefs; + GtkTreeView *list = GTK_TREE_VIEW (name_to_widget (s, "list")); + GtkListStore *model; + GtkTreeSelection *selection; + GtkCellRenderer *ren; + GtkTreeIter iter; + int i; + + g_object_get (G_OBJECT (list), + "model", &model, + NULL); + if (!model) + { + model = gtk_list_store_new (COL_LAST, G_TYPE_BOOLEAN, G_TYPE_STRING); + g_object_set (G_OBJECT (list), "model", model, NULL); + g_object_unref (model); + + ren = gtk_cell_renderer_toggle_new (); + gtk_tree_view_insert_column_with_attributes (list, COL_ENABLED, + _("Use"), ren, + "active", COL_ENABLED, + NULL); + + g_signal_connect (ren, "toggled", + G_CALLBACK (list_checkbox_cb), + s); + + ren = gtk_cell_renderer_text_new (); + gtk_tree_view_insert_column_with_attributes (list, COL_NAME, + _("Screen Saver"), ren, + "markup", COL_NAME, + NULL); + + g_signal_connect_after (list, "row_activated", + G_CALLBACK (list_activated_cb), + s); + + selection = gtk_tree_view_get_selection (list); + g_signal_connect (selection, "changed", + G_CALLBACK (list_select_changed_cb), + s); + + } + + for (i = 0; i < s->list_count; 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]); + + 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)); + + 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, "%s", + 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); + } + +#else /* !HAVE_GTK2 */ + 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 @@ -1773,10 +2222,18 @@ populate_hack_list (state *s) GtkWidget *line_hbox; GtkWidget *line_check; GtkWidget *line_label; + char *pretty_name; + Bool available_p = (hack && s->hacks_available_p [hack_number]); + + if (!hack) continue; + + /* If we're to suppress uninstalled hacks, check $PATH now. */ + if (p->ignore_uninstalled_p && !available_p) + continue; - char *pretty_name = (hack->name - ? strdup (hack->name) - : make_hack_name (hack->command)); + pretty_name = (hack->name + ? strdup (hack->name) + : make_hack_name (hack->command)); line = gtk_list_item_new (); line_hbox = gtk_hbox_new (FALSE, 0); @@ -1807,11 +2264,30 @@ populate_hack_list (state *s) 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", @@ -1820,9 +2296,9 @@ populate_hack_list (state *s) gtk_signal_connect (GTK_OBJECT (list), "unselect_child", GTK_SIGNAL_FUNC (list_unselect_cb), (gpointer) s); +#endif /* !HAVE_GTK2 */ } - static void update_list_sensitivity (state *s) { @@ -1831,21 +2307,31 @@ update_list_sensitivity (state *s) Bool checkable = (p->mode == RANDOM_HACKS); Bool blankable = (p->mode != DONT_BLANK); +#ifndef HAVE_GTK2 GtkWidget *head = name_to_widget (s, "col_head_hbox"); GtkWidget *use = name_to_widget (s, "use_col_frame"); +#endif /* HAVE_GTK2 */ GtkWidget *scroller = name_to_widget (s, "scroller"); GtkWidget *buttons = name_to_widget (s, "next_prev_hbox"); GtkWidget *blanker = name_to_widget (s, "blanking_table"); +#ifdef HAVE_GTK2 + GtkTreeView *list = GTK_TREE_VIEW (name_to_widget (s, "list")); + GtkTreeViewColumn *use = gtk_tree_view_get_column (list, COL_ENABLED); +#else /* !HAVE_GTK2 */ GtkList *list = GTK_LIST (name_to_widget (s, "list")); GList *kids = gtk_container_children (GTK_CONTAINER (list)); gtk_widget_set_sensitive (GTK_WIDGET (head), sensitive); +#endif /* !HAVE_GTK2 */ gtk_widget_set_sensitive (GTK_WIDGET (scroller), sensitive); gtk_widget_set_sensitive (GTK_WIDGET (buttons), sensitive); gtk_widget_set_sensitive (GTK_WIDGET (blanker), blankable); +#ifdef HAVE_GTK2 + gtk_tree_view_column_set_visible (use, checkable); +#else /* !HAVE_GTK2 */ if (checkable) gtk_widget_show (use); /* the "Use" column header */ else @@ -1865,6 +2351,7 @@ update_list_sensitivity (state *s) kids = kids->next; } +#endif /* !HAVE_GTK2 */ } @@ -1872,7 +2359,15 @@ static void populate_prefs_page (state *s) { saver_preferences *p = &s->prefs; - char str[100]; + + 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 + /* 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 @@ -1881,16 +2376,14 @@ populate_prefs_page (state *s) # 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) \ - sprintf (str, "%d", (((N / 1000) + 59) / 60)); \ - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, (NAME))), str) + gtk_spin_button_set_value (GTK_SPIN_BUTTON (name_to_widget (s, (NAME))), (double)((N) + 59) / (60 * 1000)) # define FMT_SECONDS(NAME,N) \ - sprintf (str, "%d", ((N) / 1000)); \ - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, (NAME))), str) + gtk_spin_button_set_value (GTK_SPIN_BUTTON (name_to_widget (s, (NAME))), (double)((N) / 1000)) FMT_MINUTES ("timeout_spinbutton", p->timeout); FMT_MINUTES ("cycle_spinbutton", p->cycle); @@ -1975,8 +2468,9 @@ populate_prefs_page (state *s) /* 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 */ @@ -2012,14 +2506,7 @@ populate_prefs_page (state *s) 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 @@ -2033,25 +2520,35 @@ populate_popup_window (state *s) 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 : 0); # else /* !HAVE_XML */ - doc_string = "Descriptions not available: no XML support compiled in."; + doc_string = _("Descriptions not available: no XML support compiled in."); # endif /* !HAVE_XML */ gtk_label_set_text (doc, (doc_string - ? doc_string - : "No description available.")); + ? _(doc_string) + : _("No description available."))); } @@ -2082,6 +2579,9 @@ sensitize_demo_widgets (state *s, Bool sensitive_p) static void fix_text_entry_sizes (state *s) { + 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", @@ -2089,7 +2589,6 @@ fix_text_entry_sizes (state *s) "-fade_spinbutton" }; int i; int width = 0; - GtkWidget *w; for (i = 0; i < countof(spinbuttons); i++) { @@ -2120,15 +2619,29 @@ fix_text_entry_sizes (state *s) 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; @@ -2138,7 +2651,7 @@ fix_text_entry_sizes (state *s) } - +#ifndef HAVE_GTK2 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...) */ @@ -2237,7 +2750,7 @@ map_prev_button_cb (GtkWidget *w, gpointer user_data) state *s = (state *) user_data; pixmapify_button (s, 0); } - +#endif /* !HAVE_GTK2 */ /* Work around a Gtk bug that causes label widgets to wrap text too early. @@ -2276,7 +2789,7 @@ eschew_gtk_lossage (GtkLabel *label) gtk_object_set_data (GTK_OBJECT (label), "gtk-aux-info", aux_info); gtk_signal_connect (GTK_OBJECT (label), "size_allocate", - you_are_not_a_unique_or_beautiful_snowflake, + GTK_SIGNAL_FUNC (you_are_not_a_unique_or_beautiful_snowflake), 0); gtk_widget_set_usize (GTK_WIDGET (label), -2, -2); @@ -2300,18 +2813,18 @@ populate_demo_window (state *s, int list_elt) if (p->mode == BLANK_ONLY) { hack = 0; - pretty_name = strdup ("Blank Screen"); + pretty_name = strdup (_("Blank Screen")); schedule_preview (s, 0); } else if (p->mode == DONT_BLANK) { hack = 0; - pretty_name = strdup ("Screen Saver Disabled"); + pretty_name = strdup (_("Screen Saver Disabled")); schedule_preview (s, 0); } 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); @@ -2329,17 +2842,17 @@ populate_demo_window (state *s, int list_elt) } if (!pretty_name) - pretty_name = strdup ("Preview"); + 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); } @@ -2348,7 +2861,7 @@ populate_demo_window (state *s, int list_elt) (hack ? (hack->visual && *hack->visual ? hack->visual - : "Any") + : _("Any")) : "")); sensitize_demo_widgets (s, (hack ? True : False)); @@ -2387,8 +2900,13 @@ sort_hack_cmp (const void *a, const void *b) 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])); + } } @@ -2396,21 +2914,44 @@ static void initialize_sort_map (state *s) { 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); - /* Initialize table to 1:1 mapping */ + /* 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); + } + + /* Initialize list->hack table to unsorted mapping, omitting nonexistent + hacks, if desired. + */ + j = 0; for (i = 0; i < p->screenhacks_count; i++) - s->list_elt_to_hack_number[i] = 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 names (once) + + /* Generate list of sortable names (once) */ sort_hack_cmp_names_kludge = (char **) calloc (sizeof(char *), p->screenhacks_count); @@ -2426,7 +2967,7 @@ initialize_sort_map (state *s) sort_hack_cmp_names_kludge[i] = name; } - /* Sort alphabetically + /* Sort list->hack map alphabetically */ qsort (s->list_elt_to_hack_number, p->screenhacks_count, @@ -2461,13 +3002,13 @@ maybe_reload_init_file (state *s) const char *f = init_file_name(); char *b; int list_elt; - GtkList *list; + GtkWidget *list; if (!f || !*f) return 0; b = (char *) malloc (strlen(f) + 1024); sprintf (b, - "Warning:\n\n" - "file \"%s\" has changed, reloading.\n", + _("Warning:\n\n" + "file \"%s\" has changed, reloading.\n"), f); warning_dialog (s->toplevel_widget, b, False, 100); free (b); @@ -2476,13 +3017,13 @@ maybe_reload_init_file (state *s) initialize_sort_map (s); list_elt = selected_list_element (s); - list = GTK_LIST (name_to_widget (s, "list")); + list = name_to_widget (s, "list"); gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL); populate_hack_list (s); force_list_select_item (s, list, list_elt, True); populate_prefs_page (s); populate_demo_window (s, list_elt); - ensure_selected_item_visible (GTK_WIDGET (list)); + ensure_selected_item_visible (list); status = 1; } @@ -2531,30 +3072,75 @@ clear_preview_window (state *s) gdk_window_set_background (window, &p->style->bg[GTK_STATE_NORMAL]); gdk_window_clear (window); - if (s->running_preview_error_p) - { - const char * const lines[] = { "No Preview", "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; - } - } + { + 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); +#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) + : 0)); +#else /* !HAVE_GTK2 */ + 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 (); +} + - /* Is there a GDK way of doing this? */ - XSync (GDK_DISPLAY(), False); +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); + } } @@ -2601,6 +3187,11 @@ 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); @@ -2619,8 +3210,13 @@ subproc_pretty_name (state *s) 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 @@ -2640,11 +3236,13 @@ reap_zombies (state *s) 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); } } } @@ -2705,7 +3303,14 @@ get_best_gl_visual (state *s) 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: @@ -2714,7 +3319,7 @@ get_best_gl_visual (state *s) 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 */ @@ -2753,7 +3358,7 @@ get_best_gl_visual (state *s) static void -kill_preview_subproc (state *s) +kill_preview_subproc (state *s, Bool reset_p) { s->running_preview_error_p = False; @@ -2778,19 +3383,19 @@ kill_preview_subproc (state *s) { 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); + (unsigned long) s->running_preview_pid, ss); free (ss); s->running_preview_pid = 0; @@ -2799,6 +3404,12 @@ kill_preview_subproc (state *s) } reap_zombies (s); + + if (reset_p) + { + reset_preview_window (s); + clear_preview_window (s); + } } @@ -2815,13 +3426,17 @@ launch_preview_subproc (state *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; } @@ -2837,10 +3452,11 @@ launch_preview_subproc (state *s) 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; @@ -2863,6 +3479,8 @@ launch_preview_subproc (state *s) { 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 @@ -2870,8 +3488,15 @@ launch_preview_subproc (state *s) 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: @@ -2883,7 +3508,8 @@ launch_preview_subproc (state *s) 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; @@ -2945,6 +3571,29 @@ hack_environment (state *s) } +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. @@ -2954,7 +3603,7 @@ update_subproc_timer (gpointer data) { 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); @@ -3017,7 +3666,7 @@ check_subproc_timer (gpointer data) { 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); } @@ -3077,7 +3726,7 @@ screen_blanked_p (void) Atom type; int format; unsigned long nitems, bytesafter; - CARD32 *data = 0; + unsigned char *dataP = 0; Display *dpy = GDK_DISPLAY(); Bool blanked_p = False; @@ -3085,14 +3734,17 @@ screen_blanked_p (void) 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; } @@ -3110,7 +3762,7 @@ check_blanked_timer (gpointer data) { 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 */ @@ -3203,9 +3855,9 @@ the_network_is_not_the_computer (state *s) if (!rversion || !*rversion) { sprintf (msg, - "Warning:\n\n" - "The XScreenSaver daemon doesn't seem to be running\n" - "on display \"%s\". Launch it now?", + _("Warning:\n\n" + "The XScreenSaver daemon doesn't seem to be running\n" + "on display \"%s\". Launch it now?"), d); } else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name)) @@ -3213,7 +3865,7 @@ the_network_is_not_the_computer (state *s) /* Warn that the two processes are running as different users. */ sprintf(msg, - "Warning:\n\n" + _("Warning:\n\n" "%s is running as user \"%s\" on host \"%s\".\n" "But the xscreensaver managing display \"%s\"\n" "is running as user \"%s\" on host \"%s\".\n" @@ -3225,12 +3877,12 @@ the_network_is_not_the_computer (state *s) "You should either re-run %s as \"%s\", or re-run\n" "xscreensaver as \"%s\".\n" "\n" - "Restart the xscreensaver daemon now?\n", - blurb(), luser, lhost, + "Restart the xscreensaver daemon now?\n"), + progname, luser, lhost, d, (ruser ? ruser : "???"), (rhost ? rhost : "???"), - blurb(), - blurb(), (ruser ? ruser : "???"), + progname, + progname, (ruser ? ruser : "???"), luser); } else if (rhost && *rhost && !!strcmp (rhost, lhost)) @@ -3238,7 +3890,7 @@ the_network_is_not_the_computer (state *s) /* Warn that the two processes are running on different hosts. */ sprintf (msg, - "Warning:\n\n" + _("Warning:\n\n" "%s is running as user \"%s\" on host \"%s\".\n" "But the xscreensaver managing display \"%s\"\n" "is running as user \"%s\" on host \"%s\".\n" @@ -3247,12 +3899,12 @@ the_network_is_not_the_computer (state *s) "if they don't see the same ~%s/.xscreensaver file) then\n" "%s won't work right.\n" "\n" - "Restart the daemon on \"%s\" as \"%s\" now?\n", - blurb(), luser, lhost, + "Restart the daemon on \"%s\" as \"%s\" now?\n"), + progname, luser, lhost, d, (ruser ? ruser : "???"), (rhost ? rhost : "???"), luser, - blurb(), + progname, lhost, luser); } else if (!!strcmp (rversion, s->short_version)) @@ -3260,13 +3912,13 @@ the_network_is_not_the_computer (state *s) /* Warn that the version numbers don't match. */ sprintf (msg, - "Warning:\n\n" + _("Warning:\n\n" "This is %s version %s.\n" "But the xscreensaver managing display \"%s\"\n" "is version %s. This could cause problems.\n" - "\n" - "Restart the xscreensaver daemon now?\n", - blurb(), s->short_version, + "\n" + "Restart the xscreensaver daemon now?\n"), + progname, s->short_version, d, rversion); } @@ -3290,13 +3942,9 @@ demo_ehandler (Display *dpy, XErrorEvent *error) { state *s = global_state_kludge; /* I hate C so much... */ fprintf (stderr, "\nX error in %s:\n", blurb()); - if (XmuPrintDefaultErrorMessage (dpy, error, stderr)) - { - kill_preview_subproc (s); - exit (-1); - } - else - fprintf (stderr, " (nonfatal.)\n"); + XmuPrintDefaultErrorMessage (dpy, error, stderr); + kill_preview_subproc (s, False); + exit (-1); return 0; } @@ -3332,6 +3980,12 @@ g_log_handler (const gchar *log_domain, GLogLevelFlags log_level, } +#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 @@ -3349,8 +4003,7 @@ const char *usage = "[--display dpy] [--prefs]" # ifdef HAVE_CRAPPLET " [--crapplet]" # endif - " [--debug]"; - + "\n\t\t [--debug] [--sync] [--no-xshm] [--configdir dir]"; static void map_popup_window_cb (GtkWidget *w, gpointer user_data) @@ -3406,6 +4059,36 @@ delayed_scroll_kludge (gpointer data) return FALSE; /* do not re-execute timer */ } +#ifdef HAVE_GTK2 + +GtkWidget * +create_xscreensaver_demo (void) +{ + GtkWidget *nb; + + nb = name_to_widget (global_state_kludge, "preview_notebook"); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), FALSE); + + return name_to_widget (global_state_kludge, "xscreensaver_demo"); +} + +GtkWidget * +create_xscreensaver_settings_dialog (void) +{ + GtkWidget *w, *box; + + box = name_to_widget (global_state_kludge, "dialog_action_area"); + + w = name_to_widget (global_state_kludge, "adv_button"); + gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (box), w, TRUE); + + w = name_to_widget (global_state_kludge, "std_button"); + gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (box), w, TRUE); + + return name_to_widget (global_state_kludge, "xscreensaver_settings_dialog"); +} + +#endif /* HAVE_GTK2 */ int main (int argc, char **argv) @@ -3418,10 +4101,24 @@ main (int argc, char **argv) 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; +#ifdef ENABLE_NLS + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + textdomain (GETTEXT_PACKAGE); + +# ifdef HAVE_GTK2 + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); +# else /* !HAVE_GTK2 */ + if (!setlocale (LC_ALL, "")) + fprintf (stderr, "%s: locale not supported by C library\n", real_progname); +# endif /* !HAVE_GTK2 */ + +#endif /* ENABLE_NLS */ + str = strrchr (real_progname, '/'); if (str) real_progname = str+1; @@ -3452,11 +4149,13 @@ main (int argc, char **argv) } #ifdef DEFAULT_ICONDIR /* from -D on compile line */ +# ifndef HAVE_GTK2 { const char *dir = DEFAULT_ICONDIR; if (*dir) add_pixmap_directory (dir); } -#endif +# endif /* !HAVE_GTK2 */ +#endif /* DEFAULT_ICONDIR */ /* This is gross, but Gtk understands --display and not -display... */ @@ -3468,36 +4167,86 @@ main (int argc, char **argv) /* We need to parse this arg really early... Sigh. */ for (i = 1; i < argc; i++) - if (argv[i] && - (!strcmp(argv[i], "--crapplet") || - !strcmp(argv[i], "--capplet"))) - { -# ifdef HAVE_CRAPPLET - int j; - crapplet_p = True; - for (j = i; j < argc; j++) /* remove it from the list */ - argv[j] = argv[j+1]; - argc--; - -# else /* !HAVE_CRAPPLET */ - fprintf (stderr, "%s: not compiled with --crapplet support\n", - real_progname); - fprintf (stderr, "%s: %s\n", real_progname, usage); - exit (1); -# endif /* !HAVE_CRAPPLET */ - } - 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--; + 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--; +# 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); +# 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--; + 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. */ @@ -3620,7 +4369,8 @@ main (int argc, char **argv) ; 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); } @@ -3632,6 +4382,9 @@ main (int argc, char **argv) was in argv[0]. */ p->db = db; + + hack_environment (s); /* must be before initialize_sort_map() */ + load_init_file (p); initialize_sort_map (s); @@ -3680,6 +4433,7 @@ main (int argc, char **argv) /* 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++; @@ -3688,7 +4442,12 @@ main (int argc, char **argv) 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); @@ -3734,13 +4493,14 @@ main (int argc, char **argv) "map", GTK_SIGNAL_FUNC(map_popup_window_cb), (gpointer) s); +#ifndef HAVE_GTK2 gtk_signal_connect (GTK_OBJECT (name_to_widget (s, "prev")), "map", GTK_SIGNAL_FUNC(map_prev_button_cb), (gpointer) s); gtk_signal_connect (GTK_OBJECT (name_to_widget (s, "next")), "map", GTK_SIGNAL_FUNC(map_next_button_cb), (gpointer) s); - +#endif /* !HAVE_GTK2 */ /* Hook up callbacks to the items on the mode menu. */ { @@ -3776,7 +4536,6 @@ main (int argc, char **argv) # 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")); @@ -3787,7 +4546,7 @@ main (int argc, char **argv) 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. */ @@ -3809,9 +4568,27 @@ main (int argc, char **argv) # 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 @@ -3853,7 +4630,7 @@ main (int argc, char **argv) int i; for (i = 0; i < p->screenhacks_count; i++) { - screenhack *hack = p->screenhacks[s->hack_number_to_list_elt[i]]; + screenhack *hack = p->screenhacks[i]; conf_data *d = load_configurator (hack->command, False); if (d) free_conf_data (d); } @@ -3868,7 +4645,7 @@ main (int argc, char **argv) # endif /* HAVE_CRAPPLET */ gtk_main (); - kill_preview_subproc (s); + kill_preview_subproc (s, False); exit (0); }