/* demo-Gtk-conf.c --- implements the dynamic configuration dialogs.
- * xscreensaver, Copyright (c) 2001, 2003 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 2001, 2003, 2004, 2006 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
*/
xmlChar *arg_set; /* command-line option to set for "yes", or null */
xmlChar *arg_unset; /* command-line option to set for "no", or null */
- xmlChar *test; /* #### no idea - enablement? */
/* select
*/
/* select_option
*/
- GList *enable;
-
GtkWidget *widget;
} parameter;
if (p->arg) free (p->arg);
if (p->arg_set) free (p->arg_set);
if (p->arg_unset) free (p->arg_unset);
- if (p->test) free (p->test);
for (rest = p->options; rest; rest = rest->next)
if (rest->data)
free_parameter ((parameter *) rest->data);
- for (rest = p->enable; rest; rest = rest->next)
- {
- free ((char *) rest->data);
- rest->data = 0;
- }
- if (p->enable) g_list_free (p->enable);
-
memset (p, ~0, sizeof(*p));
free (p);
}
if (p->invert_p) fprintf (out, " convert=\"invert\"");
if (p->arg_set) fprintf (out, " arg-set=\"%s\"", p->arg_set);
if (p->arg_unset) fprintf (out, " arg-unset=\"%s\"", p->arg_unset);
- if (p->test) fprintf (out, " test=\"%s\"", p->test);
fprintf (out, ">\n");
if (p->type == SELECT)
if (o->label) fprintf (out, " _label=\"%s\"", o->label);
if (o->arg_set) fprintf (out, " arg-set=\"%s\"", o->arg_set);
if (o->arg_unset) fprintf (out, " arg-unset=\"%s\"", o->arg_unset);
- if (o->test) fprintf (out, " test=\"%s\"", o->test);
- if (o->enable)
- {
- GList *e;
- fprintf (out, " enable=\"");
- for (e = o->enable; e; e = e->next)
- fprintf (out, "%s%s", (char *) e->data, (e->next ? "," : ""));
- fprintf (out, "\"");
- }
fprintf (out, ">\n");
}
fprintf (out, "</select>\n");
static void sanity_check_parameter (const char *filename,
const xmlChar *node_name,
parameter *p);
+static void sanity_check_text_node (const char *filename,
+ const xmlNodePtr node);
+static void sanity_check_menu_options (const char *filename,
+ const xmlChar *node_name,
+ parameter *p);
/* Allocates and returns a new `parameter' object based on the
properties in the given XML node. Returns 0 if there's nothing
else if (!strcmp (name, "file")) p->type = FILENAME;
else if (!strcmp (name, "number")) p->type = SPINBUTTON;
else if (!strcmp (name, "select")) p->type = SELECT;
+
+ else if (!strcmp (name, "xscreensaver-text") || /* these are ignored in X11 */
+ !strcmp (name, "xscreensaver-image")) /* (they are used in Cocoa) */
+ {
+ free (p);
+ return 0;
+ }
+ else if (node->type == XML_TEXT_NODE)
+ {
+ sanity_check_text_node (filename, node);
+ free (p);
+ return 0;
+ }
else
{
if (debug_p)
p->arg = xmlGetProp (node, (xmlChar *) "arg");
p->arg_set = xmlGetProp (node, (xmlChar *) "arg-set");
p->arg_unset = xmlGetProp (node, (xmlChar *) "arg-unset");
- p->test = xmlGetProp (node, (xmlChar *) "test");
/* Check for missing decimal point */
if (debug_p &&
{
if (node->type == XML_COMMENT_NODE)
return 0;
+ else if (node->type == XML_TEXT_NODE)
+ {
+ sanity_check_text_node (filename, node);
+ return 0;
+ }
else if (node->type != XML_ELEMENT_NODE)
{
if (debug_p)
else
{
parameter *s = calloc (1, sizeof(*s));
- char *enable, *e;
s->type = SELECT_OPTION;
s->id = xmlGetProp (node, (xmlChar *) "id");
s->label = xmlGetProp (node, (xmlChar *) "_label");
s->arg_set = xmlGetProp (node, (xmlChar *) "arg-set");
s->arg_unset = xmlGetProp (node, (xmlChar *) "arg-unset");
- s->test = xmlGetProp (node, (xmlChar *) "test");
- enable = (char*)xmlGetProp (node, (xmlChar *) "enable");
-
- if (enable)
- {
- enable = strdup (enable);
- e = strtok (enable, ", ");
- while (e)
- {
- s->enable = g_list_append (s->enable, strdup (e));
- e = strtok (0, ", ");
- }
- free (enable);
- }
sanity_check_parameter (filename, node->name, s);
return s;
CHECK (arg_unset, "arg-unset");
# undef CHECK
# undef WARN
+
+ if (p->type == SELECT)
+ sanity_check_menu_options (filename, node_name, p);
+}
+
+
+static void
+sanity_check_menu_options (const char *filename, const xmlChar *node_name,
+ parameter *p)
+{
+ GList *opts;
+ int noptions = 0;
+ int nulls = 0;
+ char *prefix = 0;
+
+/* fprintf (stderr, "\n## %s\n", p->id);*/
+ for (opts = p->options; opts; opts = opts->next)
+ {
+ parameter *s = (parameter *) opts->data;
+ if (!s->arg_set) nulls++;
+ noptions++;
+
+ if (s->arg_set)
+ {
+ char *a = strdup ((char *) s->arg_set);
+ char *spc = strchr (a, ' ');
+ if (spc) *spc = 0;
+ if (prefix)
+ {
+ if (strcmp (a, prefix))
+ fprintf (stderr,
+ "%s: %s: both \"%s\" and \"%s\" used in <select id=\"%s\">\n",
+ blurb(), filename, prefix, a, p->id);
+ free (prefix);
+ }
+ prefix = a;
+ }
+
+/* fprintf (stderr, "\n %s\n", s->arg_set);*/
+ }
+
+ if (prefix) free (prefix);
+ prefix = 0;
+ if (nulls > 1)
+ fprintf (stderr,
+ "%s: %s: more than one menu with no arg-set in <select id=\"%s\">\n",
+ blurb(), filename, p->id);
+}
+
+
+/* "text" nodes show up for all the non-tag text in the file, including
+ all the newlines between tags. Warn if there is text there that
+ is not whitespace.
+ */
+static void
+sanity_check_text_node (const char *filename, const xmlNodePtr node)
+{
+ const char *body = (const char *) node->content;
+ if (node->type != XML_TEXT_NODE) abort();
+ while (isspace (*body)) body++;
+ if (*body)
+ fprintf (stderr, "%s: WARNING: %s: random text present: \"%s\"\n",
+ blurb(), filename, body);
}
+/* Returns a list of strings, every switch mentioned in the parameters.
+ The strings must be freed.
+ */
+static GList *
+get_all_switches (const char *filename, GList *parms)
+{
+ GList *switches = 0;
+ GList *p;
+ for (p = parms; p; p = p->next)
+ {
+ parameter *pp = (parameter *) p->data;
+
+ if (pp->type == SELECT)
+ {
+ GList *list2 = get_all_switches (filename, pp->options);
+ switches = g_list_concat (switches, list2);
+ }
+ if (pp->arg && *pp->arg)
+ switches = g_list_append (switches, strdup ((char *) pp->arg));
+ if (pp->arg_set && *pp->arg_set)
+ switches = g_list_append (switches, strdup ((char *) pp->arg_set));
+ if (pp->arg_unset && *pp->arg_unset)
+ switches = g_list_append (switches, strdup ((char *) pp->arg_unset));
+ }
+ return switches;
+}
+
+
+/* Ensures that no switch is mentioned more than once.
+ */
+static void
+sanity_check_parameters (const char *filename, GList *parms)
+{
+ GList *list = get_all_switches (filename, parms);
+ GList *p;
+ for (p = list; p; p = p->next)
+ {
+ char *sw = (char *) p->data;
+ GList *p2;
+
+ if (*sw != '-' && *sw != '+')
+ fprintf (stderr, "%s: %s: switch does not begin with hyphen \"%s\"\n",
+ blurb(), filename, sw);
+
+ for (p2 = p->next; p2; p2 = p2->next)
+ {
+ const char *sw2 = (const char *) p2->data;
+ if (!strcmp (sw, sw2))
+ fprintf (stderr, "%s: %s: duplicate switch \"%s\"\n",
+ blurb(), filename, sw);
+ }
+
+ free (sw);
+ }
+ g_list_free (list);
+}
+
/* Helper for make_parameters()
*/
{
if (node->type == XML_ELEMENT_NODE &&
!strcmp ((char *) node->name, "screensaver"))
- return make_parameters_1 (filename, node->xmlChildrenNode, parent, &row);
+ return make_parameters_1 (filename, node->xmlChildrenNode,
+ parent, &row);
}
return 0;
}
: p->value);
gfloat si = (p->high - p->low) / 100;
gfloat pi = (p->high - p->low) / 10;
+ gfloat page_size = ((p->type == SLIDER) ? 1 : 0);
if (p->value < p->low || p->value > p->high)
{
return GTK_ADJUSTMENT (gtk_adjustment_new (value,
p->low,
- p->high + 1,
- si, pi, 1));
+ p->high + page_size,
+ si, pi, page_size));
}
return 0;
if (p->integer_p)
- sprintf (buf, "%d", (int) (value + 0.5));
+ sprintf (buf, "%d", (int) (value + (value > 0 ? 0.5 : -0.5)));
else
sprintf (buf, "%.4f", value);
char *option = rest->data;
rest->data = 0;
- if (option[0] != '-')
+ if (option[0] != '-' && option[0] != '+')
{
if (debug_p)
fprintf (stderr, "%s: WARNING: %s: not a switch: \"%s\"\n",
*/
static char *
-get_description (GList *parms)
+get_description (GList *parms, gboolean verbose_p)
{
parameter *doc = 0;
for (; parms; parms = parms->next)
{
char *d = strdup ((char *) doc->string);
char *s;
+ char *p;
for (s = d; *s; s++)
if (s[0] == '\n')
{
d[--L] = 0;
}
- return _(d);
+ /* strip off duplicated whitespaces */
+ for (s = d; *s; s++)
+ if (s[0] == ' ')
+ {
+ p = s+1;
+ while (*s == ' ')
+ s++;
+ if (*p && (s != p))
+ memmove (p, s, strlen(s)+1);
+ }
+
+#if 0
+ if (verbose_p)
+ {
+ fprintf (stderr, "%s: text read is \"%s\"\n", blurb(),doc->string);
+ fprintf (stderr, "%s: description is \"%s\"\n", blurb(), d);
+ fprintf (stderr, "%s: translation is \"%s\"\n", blurb(), _(d));
+ }
+#endif /* 0 */
+
+ return (d);
}
}
gboolean verbose_p)
{
const char *dir = hack_configuration_path;
+ char *base_program;
int L = strlen (dir);
char *file;
char *s;
if (L == 0) return 0;
- file = (char *) malloc (L + strlen (program) + 10);
+ base_program = strrchr(program, '/');
+ if (base_program) base_program++;
+ if (!base_program) base_program = (char *) program;
+
+ file = (char *) malloc (L + strlen (base_program) + 10);
data = (conf_data *) calloc (1, sizeof(*data));
strcpy (file, dir);
if (file[L-1] != '/')
file[L++] = '/';
- strcpy (file+L, program);
+ strcpy (file+L, base_program);
for (s = file+L; *s; s++)
if (*s == '/' || *s == ' ')
gtk_widget_show (table);
parms = make_parameters (file, doc->xmlRootNode, table);
+ sanity_check_parameters (file, parms);
xmlFreeDoc (doc);
data->widget = table;
data->parameters = parms;
- data->description = get_description (parms);
+ data->description = get_description (parms, verbose_p);
}
else
{