X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=driver%2Fdemo-Gtk-conf.c;h=2f03a12f04e20870e152ece5d6e37c8b9a54e31b;hp=23f5944dea4ec7e8de44f208a3d5824683996c61;hb=019de959b265701cd0c3fccbb61f2b69f06bf9ee;hpb=40eacb5812ef7c0e3374fb139afbb4f5bc8bbfb5 diff --git a/driver/demo-Gtk-conf.c b/driver/demo-Gtk-conf.c index 23f5944d..2f03a12f 100644 --- a/driver/demo-Gtk-conf.c +++ b/driver/demo-Gtk-conf.c @@ -1,5 +1,5 @@ /* demo-Gtk-conf.c --- implements the dynamic configuration dialogs. - * xscreensaver, Copyright (c) 2001, 2003 Jamie Zawinski + * xscreensaver, Copyright (c) 2001-2013 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 @@ -63,7 +63,22 @@ #include "demo-Gtk-conf.h" - +/* 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_ADJ_VALUE(a) gtk_adjustment_get_value (a) +# define GET_ADJ_UPPER(a) gtk_adjustment_get_upper (a) +# define GET_ADJ_LOWER(a) gtk_adjustment_get_lower (a) +#else +# define GET_PARENT(w) ((w)->parent) +# define GET_ADJ_VALUE(a) ((a)->value) +# define GET_ADJ_UPPER(a) ((a)->upper) +# define GET_ADJ_LOWER(a) ((a)->lower) +#endif + + extern const char *blurb (void); @@ -72,6 +87,11 @@ const char *hack_configuration_path = HACK_CONFIGURATION_PATH; static gboolean debug_p = FALSE; +#define MIN_SLIDER_WIDTH 150 +#define MIN_SPINBUTTON_WIDTH 48 +#define MIN_LABEL_WIDTH 70 + + typedef enum { COMMAND, FAKE, @@ -91,30 +111,29 @@ typedef struct { parameter_type type; - char *id; /* widget name */ - char *label; /* heading label, or null */ + xmlChar *id; /* widget name */ + xmlChar *label; /* heading label, or null */ /* command, fake, description, fakepreview, string, file */ - char *string; /* file name, description, whatever. */ + xmlChar *string; /* file name, description, whatever. */ /* slider, spinbutton */ - char *low_label; /* label for the left side */ - char *high_label; /* label for the right side */ + xmlChar *low_label; /* label for the left side */ + xmlChar *high_label; /* label for the right side */ float low; /* minimum value */ float high; /* maximum value */ float value; /* default value */ gboolean integer_p; /* whether the range is integral, or real */ - char *arg; /* command-line option to set (substitute "%") */ + xmlChar *arg; /* command-line option to set (substitute "%") */ gboolean invert_p; /* whether to flip the value and pretend the range goes from hi-low instead of low-hi. */ /* boolean, select-option */ - char *arg_set; /* command-line option to set for "yes", or null */ - char *arg_unset; /* command-line option to set for "no", or null */ - char *test; /* #### no idea - enablement? */ + xmlChar *arg_set; /* command-line option to set for "yes", or null */ + xmlChar *arg_unset; /* command-line option to set for "no", or null */ /* select */ @@ -122,16 +141,14 @@ typedef struct { /* select_option */ - GList *enable; - GtkWidget *widget; } parameter; static parameter *make_select_option (const char *file, xmlNodePtr); -static void make_parameter_widget (const char *filename, - parameter *, GtkWidget *, int *); +static void make_parameter_widget (const char *filename, + parameter *, GtkWidget *); static void browse_button_cb (GtkButton *button, gpointer user_data); @@ -150,19 +167,11 @@ free_parameter (parameter *p) 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); } @@ -202,7 +211,6 @@ describe_parameter (FILE *out, parameter *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) @@ -217,15 +225,6 @@ describe_parameter (FILE *out, parameter *p) 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, "\n"); @@ -246,9 +245,9 @@ describe_parameter (FILE *out, parameter *p) `floatp' is set to TRUE. Otherwise, it is unchanged. */ static float -xml_get_float (xmlNodePtr node, const char *name, gboolean *floatpP) +xml_get_float (xmlNodePtr node, const xmlChar *name, gboolean *floatpP) { - const char *s = xmlGetProp (node, name); + const char *s = (char *) xmlGetProp (node, name); float f; char c; if (!s || 1 != sscanf (s, "%f %c", &f, &c)) @@ -262,8 +261,13 @@ xml_get_float (xmlNodePtr node, const char *name, gboolean *floatpP) static void sanity_check_parameter (const char *filename, - const char *node_name, + 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 @@ -273,7 +277,7 @@ static parameter * make_parameter (const char *filename, xmlNodePtr node) { parameter *p; - const char *name = node->name; + const char *name = (char *) node->name; const char *convert; gboolean floatp = FALSE; @@ -293,6 +297,20 @@ make_parameter (const char *filename, xmlNodePtr node) 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") || /* ignored in X11; */ + !strcmp (name, "xscreensaver-image") || /* used in Cocoa. */ + !strcmp (name, "xscreensaver-updater")) + { + 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) @@ -304,7 +322,7 @@ make_parameter (const char *filename, xmlNodePtr node) if (p->type == SPINBUTTON) { - const char *type = xmlGetProp (node, "type"); + const char *type = (char *) xmlGetProp (node, (xmlChar *) "type"); if (!type || !strcmp (type, "spinbutton")) p->type = SPINBUTTON; else if (!strcmp (type, "slider")) p->type = SLIDER; else @@ -321,23 +339,23 @@ make_parameter (const char *filename, xmlNodePtr node) if (node->xmlChildrenNode && node->xmlChildrenNode->type == XML_TEXT_NODE && !node->xmlChildrenNode->next) - p->string = strdup (node->xmlChildrenNode->content); + p->string = (xmlChar *) + strdup ((char *) node->xmlChildrenNode->content); } - p->id = xmlGetProp (node, "id"); - p->label = xmlGetProp (node, "_label"); - p->low_label = xmlGetProp (node, "_low-label"); - p->high_label = xmlGetProp (node, "_high-label"); - p->low = xml_get_float (node, "low", &floatp); - p->high = xml_get_float (node, "high", &floatp); - p->value = xml_get_float (node, "default", &floatp); + p->id = xmlGetProp (node, (xmlChar *) "id"); + p->label = xmlGetProp (node, (xmlChar *) "_label"); + p->low_label = xmlGetProp (node, (xmlChar *) "_low-label"); + p->high_label = xmlGetProp (node, (xmlChar *) "_high-label"); + p->low = xml_get_float (node, (xmlChar *) "low", &floatp); + p->high = xml_get_float (node, (xmlChar *) "high", &floatp); + p->value = xml_get_float (node, (xmlChar *) "default", &floatp); p->integer_p = !floatp; - convert = xmlGetProp (node, "convert"); + convert = (char *) xmlGetProp (node, (xmlChar *) "convert"); p->invert_p = (convert && !strcmp (convert, "invert")); - p->arg = xmlGetProp (node, "arg"); - p->arg_set = xmlGetProp (node, "arg-set"); - p->arg_unset = xmlGetProp (node, "arg-unset"); - p->test = xmlGetProp (node, "test"); + p->arg = xmlGetProp (node, (xmlChar *) "arg"); + p->arg_set = xmlGetProp (node, (xmlChar *) "arg-set"); + p->arg_unset = xmlGetProp (node, (xmlChar *) "arg-unset"); /* Check for missing decimal point */ if (debug_p && @@ -360,7 +378,7 @@ make_parameter (const char *filename, xmlNodePtr node) } } - sanity_check_parameter (filename, name, p); + sanity_check_parameter (filename, (const xmlChar *) name, p); return p; } @@ -375,6 +393,11 @@ make_select_option (const char *filename, xmlNodePtr node) { 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) @@ -383,7 +406,7 @@ make_select_option (const char *filename, xmlNodePtr node) blurb(), filename, node->name, (int)node->type); return 0; } - else if (strcmp (node->name, "option")) + else if (strcmp ((char *) node->name, "option")) { if (debug_p) fprintf (stderr, @@ -394,27 +417,12 @@ make_select_option (const char *filename, xmlNodePtr node) else { parameter *s = calloc (1, sizeof(*s)); - char *enable, *e; s->type = SELECT_OPTION; - s->id = xmlGetProp (node, "id"); - s->label = xmlGetProp (node, "_label"); - s->arg_set = xmlGetProp (node, "arg-set"); - s->arg_unset = xmlGetProp (node, "arg-unset"); - s->test = xmlGetProp (node, "test"); - enable = xmlGetProp (node, "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); - } + 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"); sanity_check_parameter (filename, node->name, s); return s; @@ -426,7 +434,7 @@ make_select_option (const char *filename, xmlNodePtr node) when they should have typed "arg=", etc. */ static void -sanity_check_parameter (const char *filename, const char *node_name, +sanity_check_parameter (const char *filename, const xmlChar *node_name, parameter *p) { struct { @@ -530,10 +538,10 @@ sanity_check_parameter (const char *filename, const char *node_name, # define WARN(STR) \ fprintf (stderr, "%s: %s: " STR " in <%s%s id=\"%s\">\n", \ blurb(), filename, node_name, \ - (!strcmp(node_name, "number") \ + (!strcmp((char *) node_name, "number") \ ? (p->type == SPINBUTTON ? " type=spinbutton" : " type=slider")\ : ""), \ - (p->id ? p->id : "")) + (p->id ? (char *) p->id : "")) # define CHECK(SLOT,NAME) \ if (p->SLOT && !allowed.SLOT) \ WARN ("\"" NAME "\" is not a valid option"); \ @@ -554,21 +562,140 @@ sanity_check_parameter (const char *filename, const char *node_name, 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 \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() */ static GList * -make_parameters_1 (const char *filename, xmlNodePtr node, - GtkWidget *parent, int *row) +make_parameters_1 (const char *filename, xmlNodePtr node, GtkWidget *parent) { GList *list = 0; for (; node; node = node->next) { - const char *name = node->name; + const char *name = (char *) node->name; if (!strcmp (name, "hgroup") || !strcmp (name, "vgroup")) { @@ -577,17 +704,9 @@ make_parameters_1 (const char *filename, xmlNodePtr node, : gtk_vbox_new (FALSE, 0)); GList *list2; gtk_widget_show (box); + gtk_box_pack_start (GTK_BOX (parent), box, FALSE, FALSE, 0); - if (row) - gtk_table_attach (GTK_TABLE (parent), box, 0, 3, *row, *row + 1, - 0, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), box, FALSE, FALSE, 0); - - if (row) - (*row)++; - - list2 = make_parameters_1 (filename, node->xmlChildrenNode, box, 0); + list2 = make_parameters_1 (filename, node->xmlChildrenNode, box); if (list2) list = g_list_concat (list, list2); } @@ -597,7 +716,7 @@ make_parameters_1 (const char *filename, xmlNodePtr node, if (p) { list = g_list_append (list, p); - make_parameter_widget (filename, p, parent, row); + make_parameter_widget (filename, p, parent); } } } @@ -612,12 +731,11 @@ make_parameters_1 (const char *filename, xmlNodePtr node, static GList * make_parameters (const char *filename, xmlNodePtr node, GtkWidget *parent) { - int row = 0; for (; node; node = node->next) { if (node->type == XML_ELEMENT_NODE && - !strcmp (node->name, "screensaver")) - return make_parameters_1 (filename, node->xmlChildrenNode, parent, &row); + !strcmp ((char *) node->name, "screensaver")) + return make_parameters_1 (filename, node->xmlChildrenNode, parent); } return 0; } @@ -641,6 +759,7 @@ make_adjustment (const char *filename, parameter *p) : 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) { @@ -678,50 +797,83 @@ make_adjustment (const char *filename, parameter *p) return GTK_ADJUSTMENT (gtk_adjustment_new (value, p->low, - p->high + 1, - si, pi, 1)); + p->high + page_size, + si, pi, page_size)); +} + + + +static void +set_widget_min_width (GtkWidget *w, int width) +{ + GtkRequisition req; + gtk_widget_size_request (GTK_WIDGET (w), &req); + if (req.width < width) + gtk_widget_set_size_request (GTK_WIDGET (w), width, -1); } +/* If we're inside a vbox, we need to put an hbox in it, or labels appear + on top instead of to the left, and things stretch to the full width of + the window. + */ +static GtkWidget * +insert_fake_hbox (GtkWidget *parent) +{ + if (GTK_IS_VBOX (parent)) + { + GtkWidget *hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (parent), hbox, FALSE, FALSE, 4); + gtk_widget_show (hbox); + return hbox; + } + return parent; +} + + +static void +link_atk_label_to_widget(GtkWidget *label, GtkWidget *widget) +{ + AtkObject *atk_label = gtk_widget_get_accessible (label); + AtkObject *atk_widget = gtk_widget_get_accessible (widget); + + atk_object_add_relationship (atk_label, ATK_RELATION_LABEL_FOR, + atk_widget); + atk_object_add_relationship (atk_widget, ATK_RELATION_LABELLED_BY, + atk_label); +} /* Given a `parameter' struct, allocates an appropriate GtkWidget for it, and stores it in `p->widget'. - `row' is used for keeping track of our position during table layout. - `parent' must be a GtkTable or a GtkBox. + `parent' must be a GtkBox. */ static void -make_parameter_widget (const char *filename, - parameter *p, GtkWidget *parent, int *row) +make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) { - const char *label = p->label; + const char *label = (char *) p->label; if (p->widget) return; switch (p->type) { case STRING: { + GtkWidget *entry = gtk_entry_new (); + parent = insert_fake_hbox (parent); if (label) { GtkWidget *w = gtk_label_new (_(label)); + link_atk_label_to_widget (w, entry); gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_RIGHT); gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); + set_widget_min_width (GTK_WIDGET (w), MIN_LABEL_WIDTH); gtk_widget_show (w); - if (row) - gtk_table_attach (GTK_TABLE (parent), w, 0, 1, *row, *row + 1, - GTK_FILL, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); + gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); } - p->widget = gtk_entry_new (); + p->widget = entry; if (p->string) - gtk_entry_set_text (GTK_ENTRY (p->widget), p->string); - if (row) - gtk_table_attach (GTK_TABLE (parent), p->widget, 1, 3, - *row, *row + 1, - GTK_FILL, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), p->widget, FALSE, FALSE, 4); + gtk_entry_set_text (GTK_ENTRY (p->widget), (char *) p->string); + gtk_box_pack_start (GTK_BOX (parent), p->widget, FALSE, FALSE, 4); break; } case FILENAME: @@ -729,6 +881,7 @@ make_parameter_widget (const char *filename, GtkWidget *L = gtk_label_new (label ? _(label) : ""); GtkWidget *entry = gtk_entry_new (); GtkWidget *button = gtk_button_new_with_label (_("Browse...")); + link_atk_label_to_widget (L, entry); gtk_widget_show (entry); gtk_widget_show (button); p->widget = entry; @@ -739,29 +892,16 @@ make_parameter_widget (const char *filename, gtk_label_set_justify (GTK_LABEL (L), GTK_JUSTIFY_RIGHT); gtk_misc_set_alignment (GTK_MISC (L), 1.0, 0.5); + set_widget_min_width (GTK_WIDGET (L), MIN_LABEL_WIDTH); gtk_widget_show (L); if (p->string) - gtk_entry_set_text (GTK_ENTRY (entry), p->string); + gtk_entry_set_text (GTK_ENTRY (entry), (char *) p->string); - if (row) - { - gtk_table_attach (GTK_TABLE (parent), L, 0, 1, - *row, *row + 1, - GTK_FILL, 0, 0, 0); - gtk_table_attach (GTK_TABLE (parent), entry, 1, 2, - *row, *row + 1, - GTK_EXPAND | GTK_FILL, 0, 0, 0); - gtk_table_attach (GTK_TABLE (parent), button, 2, 3, - *row, *row + 1, - 0, 0, 0, 0); - } - else - { - gtk_box_pack_start (GTK_BOX (parent), L, FALSE, FALSE, 4); - gtk_box_pack_start (GTK_BOX (parent), entry, TRUE, TRUE, 4); - gtk_box_pack_start (GTK_BOX (parent), button, FALSE, FALSE, 4); - } + parent = insert_fake_hbox (parent); + gtk_box_pack_start (GTK_BOX (parent), L, FALSE, FALSE, 4); + gtk_box_pack_start (GTK_BOX (parent), entry, TRUE, TRUE, 4); + gtk_box_pack_start (GTK_BOX (parent), button, FALSE, FALSE, 4); break; } case SLIDER: @@ -773,95 +913,46 @@ make_parameter_widget (const char *filename, if (label) { labelw = gtk_label_new (_(label)); + link_atk_label_to_widget (labelw, scale); gtk_label_set_justify (GTK_LABEL (labelw), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (labelw), 0.0, 0.5); + set_widget_min_width (GTK_WIDGET (labelw), MIN_LABEL_WIDTH); gtk_widget_show (labelw); + gtk_box_pack_start (GTK_BOX (parent), labelw, FALSE, FALSE, 2); } - if (GTK_IS_VBOX (parent)) - { - /* If we're inside a vbox, we need to put an hbox in it, to get - the low/high labels to be to the left/right of the slider. - */ - GtkWidget *hbox = gtk_hbox_new (FALSE, 0); - - /* But if we have a label, put that above the slider's hbox. */ - if (labelw) - { - gtk_box_pack_start (GTK_BOX (parent), labelw, FALSE, TRUE, 2); - labelw = 0; - } - - gtk_box_pack_start (GTK_BOX (parent), hbox, TRUE, TRUE, 6); - gtk_widget_show (hbox); - parent = hbox; - } - - if (labelw) - { - if (row) - { - gtk_table_attach (GTK_TABLE (parent), labelw, - 0, 3, *row, *row + 1, - GTK_EXPAND | GTK_FILL, 0, 0, 0); - (*row)++; - } - else - { - if (GTK_IS_HBOX (parent)) - { - GtkWidget *box = gtk_vbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (parent), box, FALSE, TRUE, 0); - gtk_widget_show (box); - gtk_box_pack_start (GTK_BOX (box), labelw, FALSE, TRUE, 4); - parent = box; - box = gtk_hbox_new (FALSE, 0); - gtk_widget_show (box); - gtk_box_pack_start (GTK_BOX (parent), box, TRUE, TRUE, 0); - parent = box; - } - else - gtk_box_pack_start (GTK_BOX (parent), labelw, - FALSE, TRUE, 0); - } - } + /* Do this after 'labelw' so that it appears above, not to left. */ + parent = insert_fake_hbox (parent); if (p->low_label) { - GtkWidget *w = gtk_label_new (_(p->low_label)); + GtkWidget *w = gtk_label_new (_((char *) p->low_label)); + link_atk_label_to_widget (w, scale); gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_RIGHT); gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); + set_widget_min_width (GTK_WIDGET (w), MIN_LABEL_WIDTH); gtk_widget_show (w); - if (row) - gtk_table_attach (GTK_TABLE (parent), w, 0, 1, *row, *row + 1, - GTK_FILL, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); + gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); } gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_BOTTOM); gtk_scale_set_draw_value (GTK_SCALE (scale), debug_p); gtk_scale_set_digits (GTK_SCALE (scale), (p->integer_p ? 0 : 2)); - if (row) - gtk_table_attach (GTK_TABLE (parent), scale, 1, 2, - *row, *row + 1, - GTK_EXPAND | GTK_FILL, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), scale, TRUE, TRUE, 4); + set_widget_min_width (GTK_WIDGET (scale), MIN_SLIDER_WIDTH); + + gtk_box_pack_start (GTK_BOX (parent), scale, FALSE, FALSE, 4); gtk_widget_show (scale); if (p->high_label) { - GtkWidget *w = gtk_label_new (_(p->high_label)); + GtkWidget *w = gtk_label_new (_((char *) p->high_label)); + link_atk_label_to_widget (w, scale); gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5); + set_widget_min_width (GTK_WIDGET (w), MIN_LABEL_WIDTH); gtk_widget_show (w); - if (row) - gtk_table_attach (GTK_TABLE (parent), w, 2, 3, *row, *row + 1, - GTK_FILL, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); + gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); } p->widget = scale; @@ -873,33 +964,23 @@ make_parameter_widget (const char *filename, GtkWidget *spin = gtk_spin_button_new (adj, 15, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE); gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (spin), TRUE); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), adj->value); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), GET_ADJ_VALUE(adj)); + set_widget_min_width (GTK_WIDGET (spin), MIN_SPINBUTTON_WIDTH); if (label) { GtkWidget *w = gtk_label_new (_(label)); + link_atk_label_to_widget (w, spin); gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_RIGHT); gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); + set_widget_min_width (GTK_WIDGET (w), MIN_LABEL_WIDTH); gtk_widget_show (w); - if (row) - gtk_table_attach (GTK_TABLE (parent), w, 0, 1, *row, *row + 1, - GTK_FILL, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), w, TRUE, TRUE, 4); + parent = insert_fake_hbox (parent); + gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); } gtk_widget_show (spin); - if (row) - { - GtkWidget *hbox = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox); - gtk_table_attach (GTK_TABLE (parent), hbox, 1, 3, - *row, *row + 1, - GTK_EXPAND | GTK_FILL, 0, 8, 0); - gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, FALSE, 0); - } - else - gtk_box_pack_start (GTK_BOX (parent), spin, FALSE, FALSE, 4); + gtk_box_pack_start (GTK_BOX (parent), spin, FALSE, FALSE, 4); p->widget = spin; break; @@ -907,12 +988,10 @@ make_parameter_widget (const char *filename, case BOOLEAN: { p->widget = gtk_check_button_new_with_label (_(label)); - if (row) - gtk_table_attach (GTK_TABLE (parent), p->widget, 0, 3, - *row, *row + 1, - GTK_EXPAND | GTK_FILL, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), p->widget, FALSE, FALSE, 4); + /* Let these stretch -- doesn't hurt. + parent = insert_fake_hbox (parent); + */ + gtk_box_pack_start (GTK_BOX (parent), p->widget, FALSE, FALSE, 4); break; } case SELECT: @@ -921,33 +1000,18 @@ make_parameter_widget (const char *filename, GtkWidget *menu = gtk_menu_new (); GList *opts; - if (label && row) - { - GtkWidget *w = gtk_label_new (_(label)); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5); - gtk_widget_show (w); - gtk_table_attach (GTK_TABLE (parent), w, 0, 3, *row, *row + 1, - GTK_EXPAND | GTK_FILL, 0, 0, 0); - (*row)++; - } - for (opts = p->options; opts; opts = opts->next) { parameter *s = (parameter *) opts->data; - GtkWidget *i = gtk_menu_item_new_with_label (_(s->label)); + GtkWidget *i = gtk_menu_item_new_with_label (_((char *) s->label)); gtk_widget_show (i); gtk_menu_append (GTK_MENU (menu), i); } gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu); p->widget = opt; - if (row) - gtk_table_attach (GTK_TABLE (parent), p->widget, 0, 3, - *row, *row + 1, - GTK_EXPAND | GTK_FILL, 0, 0, 0); - else - gtk_box_pack_start (GTK_BOX (parent), p->widget, TRUE, TRUE, 4); + parent = insert_fake_hbox (parent); + gtk_box_pack_start (GTK_BOX (parent), p->widget, FALSE, FALSE, 4); break; } @@ -962,10 +1026,8 @@ make_parameter_widget (const char *filename, if (p->widget) { - gtk_widget_set_name (p->widget, p->id); + gtk_widget_set_name (p->widget, (char *) p->id); gtk_widget_show (p->widget); - if (row) - (*row)++; } } @@ -981,8 +1043,8 @@ static void file_sel_cancel (GtkWidget *button, gpointer user_data) { GtkWidget *dialog = button; - while (dialog->parent) - dialog = dialog->parent; + while (GET_PARENT (dialog)) + dialog = GET_PARENT (dialog); gtk_widget_destroy (dialog); } @@ -993,8 +1055,9 @@ file_sel_ok (GtkWidget *button, gpointer user_data) GtkWidget *entry = GTK_WIDGET (user_data); GtkWidget *dialog = button; const char *path; - while (dialog->parent) - dialog = dialog->parent; + + while (GET_PARENT (dialog)) + dialog = GET_PARENT (dialog); gtk_widget_hide (dialog); path = gtk_file_selection_get_filename (GTK_FILE_SELECTION (dialog)); @@ -1124,7 +1187,7 @@ de_stringify (char *s) static char * format_switch (parameter *p, const char *value) { - char *fmt = p->arg; + char *fmt = (char *) p->arg; char *v2; char *result, *s; if (!fmt || !value) return 0; @@ -1156,7 +1219,7 @@ parameter_to_switch (parameter *p) { case COMMAND: if (p->arg) - return strdup (p->arg); + return strdup ((char *) p->arg); else return 0; break; @@ -1167,7 +1230,7 @@ parameter_to_switch (parameter *p) const char *s = gtk_entry_get_text (GTK_ENTRY (p->widget)); char *v; if (!strcmp ((s ? s : ""), - (p->string ? p->string : ""))) + (p->string ? (char *) p->string : ""))) v = 0; /* same as default */ else v = format_switch (p, s); @@ -1186,14 +1249,15 @@ parameter_to_switch (parameter *p) char buf[255]; char *s1; float value = (p->invert_p - ? invert_range (adj->lower, adj->upper, adj->value) - 1 - : adj->value); + ? invert_range (GET_ADJ_LOWER(adj), GET_ADJ_UPPER(adj), + GET_ADJ_VALUE(adj)) - 1 + : GET_ADJ_VALUE(adj)); if (value == p->value) /* same as default */ 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); @@ -1213,8 +1277,8 @@ parameter_to_switch (parameter *p) { GtkToggleButton *b = GTK_TOGGLE_BUTTON (p->widget); const char *s = (gtk_toggle_button_get_active (b) - ? p->arg_set - : p->arg_unset); + ? (char *) p->arg_set + : (char *) p->arg_unset); if (s) return strdup (s); else @@ -1233,7 +1297,7 @@ parameter_to_switch (parameter *p) const char *s; if (!o) abort(); if (o->type != SELECT_OPTION) abort(); - s = o->arg_set; + s = (char *) o->arg_set; if (s) return strdup (s); else @@ -1251,25 +1315,29 @@ parameter_to_switch (parameter *p) All arguments will be properly quoted. */ static char * -parameters_to_cmd_line (GList *parms) +parameters_to_cmd_line (GList *parms, gboolean default_p) { int L = g_list_length (parms); int LL = 0; char **strs = (char **) calloc (sizeof (*parms), L); char *result; char *out; - int i; + int i, j; - for (i = 0; parms; parms = parms->next, i++) + for (i = 0, j = 0; parms; parms = parms->next, i++) { - char *s = parameter_to_switch ((parameter *) parms->data); - strs[i] = s; - LL += (s ? strlen(s) : 0) + 1; + parameter *p = (parameter *) parms->data; + if (!default_p || p->type == COMMAND) + { + char *s = parameter_to_switch (p); + strs[j++] = s; + LL += (s ? strlen(s) : 0) + 1; + } } result = (char *) malloc (LL + 10); out = result; - for (i = 0; i < L; i++) + for (i = 0; i < j; i++) if (strs[i]) { strcpy (out, strs[i]); @@ -1359,7 +1427,7 @@ parse_command_line_into_parameters (const char *filename, 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", @@ -1432,8 +1500,8 @@ parse_command_line_into_parameters_1 (const char *filename, { GList *p; parameter *match = 0; - int which = -1; - int index = 0; + gint which = -1; + gint index = 0; for (p = parms; p; p = p->next) { @@ -1453,7 +1521,7 @@ parse_command_line_into_parameters_1 (const char *filename, } else if (pp->arg) { - if (compare_opts (option, value, pp->arg)) + if (compare_opts (option, value, (char *) pp->arg)) { which = -1; match = pp; @@ -1461,7 +1529,7 @@ parse_command_line_into_parameters_1 (const char *filename, } else if (pp->arg_set) { - if (compare_opts (option, value, pp->arg_set)) + if (compare_opts (option, value, (char *) pp->arg_set)) { which = 1; match = pp; @@ -1469,7 +1537,7 @@ parse_command_line_into_parameters_1 (const char *filename, } else if (pp->arg_unset) { - if (compare_opts (option, value, pp->arg_unset)) + if (compare_opts (option, value, (char *) pp->arg_unset)) { which = 0; match = pp; @@ -1501,11 +1569,11 @@ parse_command_line_into_parameters_1 (const char *filename, break; case BOOLEAN: if (which != 0 && which != 1) abort(); - parameter_set_switch (match, (gpointer) which); + parameter_set_switch (match, GINT_TO_POINTER(which)); break; case SELECT_OPTION: if (which != 1) abort(); - parameter_set_switch (parent, (gpointer) index); + parameter_set_switch (parent, GINT_TO_POINTER(index)); break; default: break; @@ -1544,7 +1612,7 @@ parameter_set_switch (parameter *p, gpointer value) if (1 == sscanf ((char *) value, "%f %c", &f, &c)) { if (p->invert_p) - f = invert_range (adj->lower, adj->upper, f) - 1; + f = invert_range (GET_ADJ_LOWER(adj), GET_ADJ_UPPER(adj), f) - 1; gtk_adjustment_set_value (adj, f); } break; @@ -1552,13 +1620,13 @@ parameter_set_switch (parameter *p, gpointer value) case BOOLEAN: { GtkToggleButton *b = GTK_TOGGLE_BUTTON (p->widget); - gtk_toggle_button_set_active (b, (int) value); + gtk_toggle_button_set_active (b, GPOINTER_TO_INT(value)); break; } case SELECT: { gtk_option_menu_set_history (GTK_OPTION_MENU (p->widget), - (int) value); + GPOINTER_TO_INT(value)); break; } default: @@ -1580,7 +1648,7 @@ restore_defaults (const char *progname, GList *parms) case FILENAME: { gtk_entry_set_text (GTK_ENTRY (p->widget), - (p->string ? p->string : "")); + (p->string ? (char *) p->string : "")); break; } case SLIDER: @@ -1641,7 +1709,7 @@ restore_defaults (const char *progname, GList *parms) */ static char * -get_description (GList *parms) +get_description (GList *parms, gboolean verbose_p) { parameter *doc = 0; for (; parms; parms = parms->next) @@ -1658,8 +1726,9 @@ get_description (GList *parms) return 0; else { - char *d = strdup (doc->string); + char *d = strdup ((char *) doc->string); char *s; + char *p; for (s = d; *s; s++) if (s[0] == '\n') { @@ -1667,6 +1736,8 @@ get_description (GList *parms) s++; else if (s[1] == ' ' || s[1] == '\t') s++; /* next line is indented: leave newline */ + else if (!strncmp(s+1, "http:", 5)) + s++; /* next line begins a URL: leave newline */ else s[0] = ' '; /* delete newline to un-fold this line */ } @@ -1686,7 +1757,27 @@ get_description (GList *parms) 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); } } @@ -1699,6 +1790,7 @@ load_configurator_1 (const char *program, const char *arguments, gboolean verbose_p) { const char *dir = hack_configuration_path; + char *base_program; int L = strlen (dir); char *file; char *s; @@ -1707,13 +1799,17 @@ load_configurator_1 (const char *program, const char *arguments, 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 == ' ') @@ -1730,7 +1826,7 @@ load_configurator_1 (const char *program, const char *arguments, char chars[1024]; xmlParserCtxtPtr ctxt; xmlDocPtr doc = 0; - GtkWidget *table; + GtkWidget *vbox0; GList *parms; if (verbose_p) @@ -1754,13 +1850,11 @@ load_configurator_1 (const char *program, const char *arguments, /* Parsed the XML file. Now make some widgets. */ - table = gtk_table_new (1, 3, FALSE); - gtk_table_set_row_spacings (GTK_TABLE (table), 4); - gtk_table_set_col_spacings (GTK_TABLE (table), 4); - gtk_container_set_border_width (GTK_CONTAINER (table), 8); - gtk_widget_show (table); + vbox0 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox0); - parms = make_parameters (file, doc->xmlRootNode, table); + parms = make_parameters (file, doc->xmlRootNode, vbox0); + sanity_check_parameters (file, parms); xmlFreeDoc (doc); @@ -1768,9 +1862,9 @@ load_configurator_1 (const char *program, const char *arguments, if (arguments && *arguments) parse_command_line_into_parameters (program, arguments, parms); - data->widget = table; + data->widget = vbox0; data->parameters = parms; - data->description = get_description (parms); + data->description = get_description (parms, verbose_p); } else { @@ -1781,7 +1875,7 @@ load_configurator_1 (const char *program, const char *arguments, p = calloc (1, sizeof(*p)); p->type = COMMAND; - p->arg = strdup (arguments); + p->arg = (xmlChar *) strdup (arguments); data->parameters = g_list_append (0, (gpointer) p); } @@ -1846,9 +1940,9 @@ load_configurator (const char *full_command_line, gboolean verbose_p) char * -get_configurator_command_line (conf_data *data) +get_configurator_command_line (conf_data *data, gboolean default_p) { - char *args = parameters_to_cmd_line (data->parameters); + char *args = parameters_to_cmd_line (data->parameters, default_p); char *result = (char *) malloc (strlen (data->progname) + strlen (args) + 2); strcpy (result, data->progname);