[gtk/stackpage: 4/11] builder tool: Rewrite the simplify command
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/stackpage: 4/11] builder tool: Rewrite the simplify command
- Date: Fri, 8 Feb 2019 05:10:43 +0000 (UTC)
commit 59152b8a8d092c81d0ed020ec97834339cf7f4a7
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Feb 7 07:12:15 2019 -0500
builder tool: Rewrite the simplify command
Rewrite the builder-tool simplify command to have
a full parse tree around, and perform simplifications
on that tree. This lets us rewrite GtkStack and turn
child properties into child meta objects.
gtk/tools/gtk-builder-tool-simplify.c | 875 ++++++++++++++++++----------------
gtk/tools/gtk-builder-tool.c | 1 +
2 files changed, 472 insertions(+), 404 deletions(-)
---
diff --git a/gtk/tools/gtk-builder-tool-simplify.c b/gtk/tools/gtk-builder-tool-simplify.c
index ec3cd271ec..55bcc0edf2 100644
--- a/gtk/tools/gtk-builder-tool-simplify.c
+++ b/gtk/tools/gtk-builder-tool-simplify.c
@@ -27,26 +27,216 @@
#include <gtk/gtk.h>
#include "gtkbuilderprivate.h"
+typedef struct Element Element;
+struct Element {
+ Element *parent;
+ char *element_name;
+ char **attribute_names;
+ char **attribute_values;
+ char *data;
+ GList *children;
+};
+
+static void
+free_element (gpointer data)
+{
+ Element *element = data;
+ g_list_free_full (element->children, free_element);
+ g_free (element->element_name);
+ g_strfreev (element->attribute_names);
+ g_strfreev (element->attribute_values);
+ g_free (element->data);
+ g_free (element);
+}
typedef struct {
- GtkBuilder *builder;
- GList *classes;
- gboolean packing;
- gboolean packing_started;
- gboolean cell_packing;
- gboolean cell_packing_started;
- gint in_child;
- gint child_started;
- gchar **attribute_names;
- gchar **attribute_values;
+ Element *root;
+ Element *current;
GString *value;
- gboolean unclosed_starttag;
- gint indent;
+ GtkBuilder *builder;
char *input_filename;
char *output_filename;
FILE *output;
+ gboolean convert3to4;
} MyParserData;
+static void
+start_element (GMarkupParseContext *context,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ MyParserData *data = user_data;
+ Element *elt;
+
+ elt = g_new0 (Element, 1);
+ elt->parent = data->current;
+ elt->element_name = g_strdup (element_name);
+ elt->attribute_names = g_strdupv ((char **)attribute_names);
+ elt->attribute_values = g_strdupv ((char **)attribute_values);
+
+ if (data->current)
+ data->current->children = g_list_append (data->current->children, elt);
+ data->current = elt;
+
+ if (data->root == NULL)
+ data->root = elt;
+
+ g_string_truncate (data->value, 0);
+}
+
+static void
+end_element (GMarkupParseContext *context,
+ const char *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ MyParserData *data = user_data;
+
+ data->current->data = g_strdup (data->value->str);
+
+ data->current = data->current->parent;
+}
+
+static void
+text (GMarkupParseContext *context,
+ const char *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ MyParserData *data = user_data;
+
+ if (data->value)
+ {
+ g_string_append_len (data->value, text, text_len);
+ return;
+ }
+}
+
+static GMarkupParser parser = {
+ start_element,
+ end_element,
+ text,
+ NULL,
+ NULL
+};
+
+static const gchar *
+canonical_boolean_value (MyParserData *data,
+ const gchar *string)
+{
+ GValue value = G_VALUE_INIT;
+ gboolean b = FALSE;
+
+ if (gtk_builder_value_from_string_type (data->builder, G_TYPE_BOOLEAN, string, &value, NULL))
+ b = g_value_get_boolean (&value);
+
+ return b ? "1" : "0";
+}
+
+/* A number of properties unfortunately can't be omitted even
+ * if they are nominally set to their default value. In many
+ * cases, this is due to subclasses not overriding the default
+ * value from the superclass.
+ */
+static gboolean
+needs_explicit_setting (const gchar *class_name,
+ const gchar *property_name,
+ gboolean packing)
+{
+ struct _Prop {
+ const char *class;
+ const char *property;
+ gboolean packing;
+ } props[] = {
+ { "GtkAboutDialog", "program-name", 0 },
+ { "GtkCalendar", "year", 0 },
+ { "GtkCalendar", "month", 0 },
+ { "GtkCalendar", "day", 0 },
+ { "GtkPlacesSidebar", "show-desktop", 0 },
+ { "GtkRadioButton", "draw-indicator", 0 },
+ { "GtkGrid", "left-attach", 1 },
+ { "GtkGrid", "top-attach", 1 },
+ { "GtkWidget", "hexpand", 0 },
+ { "GtkWidget", "vexpand", 0 },
+ };
+ gchar *canonical_name;
+ gboolean found;
+ gint k;
+
+ canonical_name = g_strdup (property_name);
+ g_strdelimit (canonical_name, "_", '-');
+
+ found = FALSE;
+ for (k = 0; k < G_N_ELEMENTS (props); k++)
+ {
+ if (strcmp (class_name, props[k].class) == 0 &&
+ strcmp (canonical_name, props[k].property) == 0 &&
+ packing == props[k].packing)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ g_free (canonical_name);
+
+ return found;
+}
+
+static gboolean
+is_pcdata_element (Element *element)
+{
+ /* elements that can contain text */
+ const char *names[] = {
+ "property",
+ "attribute",
+ "action-widget",
+ "pattern",
+ "mime-type",
+ "col",
+ "item",
+ NULL,
+ };
+
+ if (g_str_equal (element->element_name, "property") &&
+ (g_strv_contains ((const char * const *)element->attribute_names, "bind-source") ||
+ g_strv_contains ((const char * const *)element->attribute_names, "bind_source")))
+ return FALSE;
+
+ if (g_strv_contains (names, element->element_name))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+is_container_element (Element *element)
+{
+ /* elements that just hold a list of things and
+ * can be omitted when they have no children
+ */
+ const char *names[] = {
+ "packing",
+ "cell-packing",
+ "attributes",
+ "action-widgets",
+ "patterns",
+ "mime-types",
+ "attributes",
+ "row",
+ "items"
+ };
+
+ if (g_strv_contains (names, element->element_name))
+ return TRUE;
+
+ return FALSE;
+}
+
static void
canonicalize_key (gchar *key)
{
@@ -71,7 +261,9 @@ canonicalize_key (gchar *key)
static GParamSpec *
get_property_pspec (MyParserData *data,
const gchar *class_name,
- const gchar *property_name)
+ const gchar *property_name,
+ gboolean packing,
+ gboolean cell_packing)
{
GType type;
GObjectClass *class;
@@ -81,9 +273,7 @@ get_property_pspec (MyParserData *data,
type = g_type_from_name (class_name);
if (type == G_TYPE_INVALID)
{
- GtkBuilder *builder = gtk_builder_new ();
- type = gtk_builder_get_type_from_name (builder, class_name);
- g_object_unref (builder);
+ type = gtk_builder_get_type_from_name (data->builder, class_name);
if (type == G_TYPE_INVALID)
return NULL;
}
@@ -91,9 +281,9 @@ get_property_pspec (MyParserData *data,
class = g_type_class_ref (type);
canonical_name = g_strdup (property_name);
canonicalize_key (canonical_name);
- if (data->packing)
+ if (packing)
pspec = gtk_container_class_find_child_property (class, canonical_name);
- else if (data->cell_packing)
+ else if (cell_packing)
{
GObjectClass *cell_class;
@@ -110,25 +300,26 @@ get_property_pspec (MyParserData *data,
return pspec;
}
-
static gboolean
value_is_default (MyParserData *data,
const gchar *class_name,
const gchar *property_name,
- const gchar *value_string)
+ const gchar *value_string,
+ gboolean packing,
+ gboolean cell_packing)
{
GValue value = { 0, };
gboolean ret;
GError *error = NULL;
GParamSpec *pspec;
- pspec = get_property_pspec (data, class_name, property_name);
+ pspec = get_property_pspec (data, class_name, property_name, packing, cell_packing);
if (pspec == NULL)
{
- if (data->packing)
+ if (packing)
g_printerr (_("Packing property %s::%s not found\n"), class_name, property_name);
- else if (data->cell_packing)
+ else if (cell_packing)
g_printerr (_("Cell property %s::%s not found\n"), class_name, property_name);
else
g_printerr (_("Property %s::%s not found\n"), class_name, property_name);
@@ -151,73 +342,163 @@ value_is_default (MyParserData *data,
return ret;
}
+static const char *
+get_class_name (Element *element)
+{
+ Element *parent = element->parent;
+ int i;
+
+ if (g_str_equal (element->element_name, "object"))
+ parent = element;
+
+ if (g_str_equal (parent->element_name, "packing"))
+ parent = parent->parent->parent; /* child - object */
+
+ if (g_str_equal (parent->element_name, "object"))
+ {
+ for (i = 0; parent->attribute_names[i]; i++)
+ {
+ if (g_str_equal (parent->attribute_names[i], "class"))
+ return parent->attribute_values[i];
+ }
+ }
+ else if (g_str_equal (parent->element_name, "template"))
+ {
+ for (i = 0; parent->attribute_names[i]; i++)
+ {
+ if (g_str_equal (parent->attribute_names[i], "parent"))
+ return parent->attribute_values[i];
+ }
+ }
+
+ return NULL;
+}
+
static gboolean
-property_is_boolean (MyParserData *data,
- const gchar *class_name,
- const gchar *property_name)
+property_is_boolean (Element *element,
+ MyParserData *data)
{
GParamSpec *pspec;
+ gboolean packing = FALSE;
+ const char *class_name;
+ const char *property_name;
+ int i;
+
+ if (g_str_equal (element->parent->element_name, "packing"))
+ packing = TRUE;
+
+ class_name = get_class_name (element);
+ property_name = "";
+
+ for (i = 0; element->attribute_names[i]; i++)
+ {
+ if (strcmp (element->attribute_names[i], "name") == 0)
+ property_name = (const gchar *)element->attribute_values[i];
+ }
- pspec = get_property_pspec (data, class_name, property_name);
+ pspec = get_property_pspec (data, class_name, property_name, packing, FALSE);
if (pspec)
return G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN;
return FALSE;
}
-static const gchar *
-canonical_boolean_value (MyParserData *data,
- const gchar *string)
+static gboolean
+property_can_be_omitted (Element *element,
+ MyParserData *data)
{
- GValue value = G_VALUE_INIT;
- gboolean b = FALSE;
+ gint i;
+ gboolean bound;
+ gboolean translatable;
+ const gchar *class_name;
+ const gchar *property_name;
+ const gchar *value_string;
+ gboolean packing = FALSE;
+ gboolean cell_packing = FALSE;
- if (gtk_builder_value_from_string_type (data->builder, G_TYPE_BOOLEAN, string, &value, NULL))
- b = g_value_get_boolean (&value);
+ if (g_str_equal (element->parent->element_name, "packing"))
+ packing = TRUE;
+ if (g_str_equal (element->parent->element_name, "cell-packing"))
+ cell_packing = TRUE;
- return b ? "1" : "0";
+ class_name = get_class_name (element);
+ property_name = "";
+ value_string = element->data;
+
+ bound = FALSE;
+ translatable = FALSE;
+ for (i = 0; element->attribute_names[i]; i++)
+ {
+ if (strcmp (element->attribute_names[i], "bind-source") == 0 ||
+ strcmp (element->attribute_names[i], "bind_source") == 0)
+ bound = TRUE;
+ else if (strcmp (element->attribute_names[i], "translatable") == 0)
+ translatable = TRUE;
+ else if (strcmp (element->attribute_names[i], "name") == 0)
+ property_name = (const gchar *)element->attribute_values[i];
+ }
+
+ if (translatable)
+ return FALSE;
+
+ if (bound)
+ return FALSE;
+
+ if (needs_explicit_setting (class_name, property_name, packing))
+ return FALSE;
+
+ return value_is_default (data, class_name, property_name, value_string, packing, cell_packing);
}
-/* A number of properties unfortunately can't be omitted even
- * if they are nominally set to their default value. In many
- * cases, this is due to subclasses not overriding the default
- * value from the superclass.
- */
static gboolean
-needs_explicit_setting (MyParserData *data,
- const gchar *class_name,
- const gchar *property_name)
+property_has_been_removed (Element *element,
+ MyParserData *data)
{
+ const gchar *class_name;
+ const gchar *property_name;
+ gboolean packing = FALSE;
struct _Prop {
const char *class;
const char *property;
gboolean packing;
} props[] = {
- { "GtkAboutDialog", "program-name", 0 },
- { "GtkCalendar", "year", 0 },
- { "GtkCalendar", "month", 0 },
- { "GtkCalendar", "day", 0 },
- { "GtkPlacesSidebar", "show-desktop", 0 },
- { "GtkRadioButton", "draw-indicator", 0 },
- { "GtkGrid", "left-attach", 1 },
- { "GtkGrid", "top-attach", 1 },
- { "GtkWidget", "hexpand", 0 },
- { "GtkWidget", "vexpand", 0 },
- { NULL, NULL, 0 }
+ { "GtkActionBar", "position", 1 },
+ { "GtkButtonBox", "secondary", 1 },
+ { "GtkButtonBox", "non-homogeneous", 1 },
+ { "GtkBox", "pack-type", 1 },
+ { "GtkBox", "position", 1 },
+ { "GtkHeaderBar", "position", 1 },
+ { "GtkPopoverMenu", "position", 1 },
+ { "GtkMenu", "left-attach", 1 },
+ { "GtkMenu", "right-attach", 1 },
+ { "GtkMenu", "top-attach", 1 },
+ { "GtkMenu", "bottom-attach", 1 }
};
gchar *canonical_name;
gboolean found;
- gint k;
+ gint i, k;
+
+ if (g_str_equal (element->parent->element_name, "packing"))
+ packing = TRUE;
+
+ class_name = get_class_name (element);
+ property_name = "";
+
+ for (i = 0; element->attribute_names[i]; i++)
+ {
+ if (strcmp (element->attribute_names[i], "name") == 0)
+ property_name = (const gchar *)element->attribute_values[i];
+ }
canonical_name = g_strdup (property_name);
g_strdelimit (canonical_name, "_", '-');
found = FALSE;
- for (k = 0; props[k].class; k++)
+ for (k = 0; k < G_N_ELEMENTS (props); k++)
{
if (strcmp (class_name, props[k].class) == 0 &&
strcmp (canonical_name, props[k].property) == 0 &&
- data->packing == props[k].packing)
+ packing == props[k].packing)
{
found = TRUE;
break;
@@ -229,389 +510,177 @@ needs_explicit_setting (MyParserData *data,
return found;
}
-static void
-maybe_start_packing (MyParserData *data)
+static Element *
+rewrite_stack_child (Element *child, MyParserData *data)
{
- if (data->packing)
- {
- if (!data->packing_started)
- {
- g_fprintf (data->output, "%*s<packing>\n", data->indent, "");
- data->indent += 2;
- data->packing_started = TRUE;
- }
- }
+ Element *object = NULL;
+ Element *packing = NULL;
+ Element *new_object;
+ Element *prop;
+ GList *l;
+
+ if (!g_str_equal (child->element_name, "child"))
+ return child;
+
+ for (l = child->children; l; l = l->next)
+ {
+ Element *elt = l->data;
+ if (g_str_equal (elt->element_name, "object"))
+ object = elt;
+ else if (g_str_equal (elt->element_name, "packing"))
+ packing = elt;
+ }
+
+ if (!packing)
+ return child;
+
+ new_object = g_new0 (Element, 1);
+ new_object->element_name = g_strdup ("object");
+ new_object->attribute_names = g_new0 (char *, 2);
+ new_object->attribute_names[0] = g_strdup ("class");
+ new_object->attribute_values = g_new0 (char *, 2);
+ new_object->attribute_values[0] = g_strdup ("GtkStackPage");
+ new_object->children = packing->children;
+ packing->children = NULL;
+
+ prop = g_new0 (Element, 1);
+ prop->element_name = g_strdup ("property");
+ prop->attribute_names = g_new0 (char *, 2);
+ prop->attribute_names[0] = g_strdup ("name");
+ prop->attribute_values = g_new0 (char *, 2);
+ prop->attribute_values[0] = g_strdup ("child");
+ prop->children = g_list_append (prop->children, object);
+ new_object->children = g_list_append (new_object->children, prop);
+
+ g_list_free (child->children);
+ child->children = g_list_append (NULL, new_object);
+
+ return child;
}
static void
-maybe_start_cell_packing (MyParserData *data)
+rewrite_stack (Element *element,
+ MyParserData *data)
{
- if (data->cell_packing)
- {
- if (!data->cell_packing_started)
- {
- g_fprintf (data->output, "%*s<cell-packing>\n", data->indent, "");
- data->indent += 2;
- data->cell_packing_started = TRUE;
- }
- }
-}
+ GList *l, *new_children;
-static void
-maybe_start_child (MyParserData *data)
-{
- if (data->in_child > 0)
+ new_children = NULL;
+ for (l = element->children; l; l = l->next)
{
- if (data->child_started < data->in_child)
- {
- g_fprintf (data->output, "%*s<child>\n", data->indent, "");
- data->indent += 2;
- data->child_started += 1;
- }
+ Element *child = l->data;
+ new_children = g_list_append (new_children, rewrite_stack_child (child, data));
}
+
+ g_list_free (element->children);
+ element->children = new_children;
}
-static void
-maybe_emit_property (MyParserData *data)
+static gboolean
+simplify_element (Element *element,
+ MyParserData *data)
{
- gint i;
- gboolean bound;
- gboolean translatable;
- gchar *escaped;
- const gchar *class_name;
- const gchar *property_name;
- const gchar *value_string;
+ GList *l;
- class_name = (const gchar *)data->classes->data;
- property_name = "";
- value_string = (const gchar *)data->value->str;
-
- bound = FALSE;
- translatable = FALSE;
- for (i = 0; data->attribute_names[i]; i++)
+ if (!is_pcdata_element (element))
+ g_clear_pointer (&element->data, g_free);
+ else if (g_str_equal (element->element_name, "property") &&
+ property_is_boolean (element, data))
{
- if (strcmp (data->attribute_names[i], "bind-source") == 0 ||
- strcmp (data->attribute_names[i], "bind_source") == 0)
- bound = TRUE;
- else if (strcmp (data->attribute_names[i], "translatable") == 0)
- translatable = TRUE;
- else if (strcmp (data->attribute_names[i], "name") == 0)
- property_name = (const gchar *)data->attribute_values[i];
+ const char *b = canonical_boolean_value (data, element->data);
+ g_free (element->data);
+ element->data = g_strdup (b);
}
- if (!translatable &&
- !bound &&
- !needs_explicit_setting (data, class_name, property_name))
+ l = element->children;
+ while (l)
{
- for (i = 0; data->attribute_names[i]; i++)
+ GList *next = l->next;
+ Element *child = l->data;
+ if (simplify_element (child, data))
{
- if (strcmp (data->attribute_names[i], "name") == 0)
- {
- if (data->classes == NULL)
- break;
-
- if (value_is_default (data, class_name, property_name, value_string))
- return;
- }
+ element->children = g_list_remove (element->children, child);
+ free_element (child);
}
+ l = next;
}
- maybe_start_packing (data);
- maybe_start_cell_packing (data);
-
- g_fprintf (data->output, "%*s<property", data->indent, "");
- for (i = 0; data->attribute_names[i]; i++)
- {
- if (!translatable &&
- (strcmp (data->attribute_names[i], "comments") == 0 ||
- strcmp (data->attribute_names[i], "context") == 0))
- continue;
-
- escaped = g_markup_escape_text (data->attribute_values[i], -1);
-
- if (strcmp (data->attribute_names[i], "name") == 0)
- canonicalize_key (escaped);
+ if (is_container_element (element) && element->children == NULL)
+ return TRUE;
- g_fprintf (data->output, " %s=\"%s\"", data->attribute_names[i], escaped);
- g_free (escaped);
- }
+ if (g_str_equal (element->element_name, "property") &&
+ property_can_be_omitted (element, data))
+ return TRUE;
- if (bound)
- {
- g_fprintf (data->output, "/>\n");
- }
- else
+ if (data->convert3to4)
{
- g_fprintf (data->output, ">");
- if (property_is_boolean (data, class_name, property_name))
- {
- g_fprintf (data->output, "%s", canonical_boolean_value (data, value_string));
- }
- else
- {
- escaped = g_markup_escape_text (value_string, -1);
- g_fprintf (data->output, "%s", escaped);
- g_free (escaped);
- }
- g_fprintf (data->output, "</property>\n");
+ if (g_str_equal (element->element_name, "object") &&
+ g_str_equal (get_class_name (element), "GtkStack"))
+ rewrite_stack (element, data);
+
+ if (g_str_equal (element->element_name, "property") &&
+ property_has_been_removed (element, data))
+ return TRUE;
}
+
+ return FALSE;
}
static void
-maybe_close_starttag (MyParserData *data)
+simplify_tree (MyParserData *data)
{
- if (data->unclosed_starttag)
- {
- g_fprintf (data->output, ">\n");
- data->unclosed_starttag = FALSE;
- }
+ simplify_element (data->root, data);
}
-static gboolean
-stack_is (GMarkupParseContext *context,
- ...)
+static void
+dump_element (Element *element,
+ FILE *output,
+ int indent)
{
- va_list args;
- gchar *s, *p;
- const GSList *stack;
-
- stack = g_markup_parse_context_get_element_stack (context);
-
- va_start (args, context);
- s = va_arg (args, gchar *);
- while (s)
+ g_fprintf (output, "%*s<%s", indent, "", element->element_name);
+ if (element->attribute_names[0])
{
- if (stack == NULL)
- {
- va_end (args);
- return FALSE;
- }
-
- p = (gchar *)stack->data;
- if (strcmp (s, p) != 0)
+ int i;
+ for (i = 0; element->attribute_names[i]; i++)
{
- va_end (args);
- return FALSE;
+ char *escaped = g_markup_escape_text (element->attribute_values[i], -1);
+ g_fprintf (output, " %s=\"%s\"", element->attribute_names[i], escaped);
+ g_free (escaped);
}
-
- s = va_arg (args, gchar *);
- stack = stack->next;
- }
-
- va_end (args);
- return TRUE;
-}
-
-static void
-start_element (GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data,
- GError **error)
-{
- gint i;
- gchar *escaped;
- MyParserData *data = user_data;
-
- maybe_close_starttag (data);
-
- if (strcmp (element_name, "property") == 0)
- {
- g_assert (data->attribute_names == NULL);
- g_assert (data->attribute_values == NULL);
- g_assert (data->value == NULL);
-
- data->attribute_names = g_strdupv ((gchar **)attribute_names);
- data->attribute_values = g_strdupv ((gchar **)attribute_values);
- data->value = g_string_new ("");
-
- return;
}
- else if (strcmp (element_name, "packing") == 0)
+ if (element->children || element->data)
{
- data->packing = TRUE;
- data->packing_started = FALSE;
+ g_fprintf (output, ">");
- return;
- }
- else if (strcmp (element_name, "cell-packing") == 0)
- {
- data->cell_packing = TRUE;
- data->cell_packing_started = FALSE;
-
- return;
- }
- else if (strcmp (element_name, "child") == 0)
- {
- data->in_child += 1;
-
- if (attribute_names[0] == NULL)
- return;
-
- data->child_started += 1;
- }
- else if (strcmp (element_name, "attribute") == 0)
- {
- /* attribute in label has no content */
- if (data->classes == NULL ||
- strcmp ((gchar *)data->classes->data, "GtkLabel") != 0)
- data->value = g_string_new ("");
- }
- else if (stack_is (context, "item", "items", NULL) ||
- stack_is (context, "action-widget", "action-widgets", NULL) ||
- stack_is (context, "mime-type", "mime-types", NULL) ||
- stack_is (context, "pattern", "patterns", NULL) ||
- stack_is (context, "application", "applications", NULL) ||
- stack_is (context, "col", "row", "data", NULL) ||
- stack_is (context, "mark", "marks", NULL) ||
- stack_is (context, "action", "accessibility", NULL))
- {
- data->value = g_string_new ("");
- }
- else if (strcmp (element_name, "placeholder") == 0)
- {
- return;
- }
- else if (strcmp (element_name, "object") == 0 ||
- strcmp (element_name, "template") == 0)
- {
- maybe_start_child (data);
-
- for (i = 0; attribute_names[i]; i++)
+ if (element->children)
{
- if (strcmp (attribute_names[i], "class") == 0)
+ GList *l;
+
+ g_fprintf (output, "\n");
+ for (l = element->children; l; l = l->next)
{
- data->classes = g_list_prepend (data->classes,
- g_strdup (attribute_values[i]));
- break;
+ Element *child = l->data;
+ dump_element (child, output, indent + 2);
}
+ g_fprintf (output, "%*s", indent, "");
}
- }
-
- g_fprintf (data->output, "%*s<%s", data->indent, "", element_name);
- for (i = 0; attribute_names[i]; i++)
- {
- escaped = g_markup_escape_text (attribute_values[i], -1);
- g_fprintf (data->output, " %s=\"%s\"", attribute_names[i], escaped);
- g_free (escaped);
- }
- data->unclosed_starttag = TRUE;
- data->indent += 2;
-}
-
-static void
-end_element (GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data,
- GError **error)
-{
- MyParserData *data = user_data;
-
- if (strcmp (element_name, "property") == 0)
- {
- maybe_emit_property (data);
-
- g_clear_pointer (&data->attribute_names, g_strfreev);
- g_clear_pointer (&data->attribute_values, g_strfreev);
- g_string_free (data->value, TRUE);
- data->value = NULL;
- return;
- }
- else if (strcmp (element_name, "packing") == 0)
- {
- data->packing = FALSE;
- if (!data->packing_started)
- return;
- }
- else if (strcmp (element_name, "cell-packing") == 0)
- {
- data->cell_packing = FALSE;
- if (!data->cell_packing_started)
- return;
- }
- else if (strcmp (element_name, "child") == 0)
- {
- data->in_child -= 1;
- if (data->child_started == data->in_child)
- return;
- data->child_started -= 1;
- }
- else if (strcmp (element_name, "placeholder") == 0)
- {
- return;
- }
- else if (strcmp (element_name, "object") == 0 ||
- strcmp (element_name, "template") == 0)
- {
- g_free (data->classes->data);
- data->classes = g_list_delete_link (data->classes, data->classes);
- }
-
- if (data->value != NULL)
- {
- gchar *escaped;
-
- if (data->unclosed_starttag)
- g_fprintf (data->output, ">");
-
- escaped = g_markup_escape_text (data->value->str, -1);
- g_fprintf (data->output, "%s</%s>\n", escaped, element_name);
- g_free (escaped);
-
- g_string_free (data->value, TRUE);
- data->value = NULL;
- }
- else
- {
- if (data->unclosed_starttag)
- g_fprintf (data->output, "/>\n");
else
- g_fprintf (data->output, "%*s</%s>\n", data->indent - 2, "", element_name);
- }
-
- data->indent -= 2;
- data->unclosed_starttag = FALSE;
-}
-
-static void
-text (GMarkupParseContext *context,
- const gchar *text,
- gsize text_len,
- gpointer user_data,
- GError **error)
-{
- MyParserData *data = user_data;
-
- if (data->value)
- {
- g_string_append_len (data->value, text, text_len);
- return;
+ {
+ char *escaped = g_markup_escape_text (element->data, -1);
+ g_fprintf (output, "%s", escaped);
+ g_free (escaped);
+ }
+ g_fprintf (output, "</%s>\n", element->element_name);
}
+ else
+ g_fprintf (output, "/>\n");
}
static void
-passthrough (GMarkupParseContext *context,
- const gchar *text,
- gsize text_len,
- gpointer user_data,
- GError **error)
+dump_tree (MyParserData *data)
{
- MyParserData *data = user_data;
-
- maybe_close_starttag (data);
-
- g_fprintf (data->output, "%*s%s\n", data->indent, "", text);
+ dump_element (data->root, data->output, 0);
}
-GMarkupParser parser = {
- start_element,
- end_element,
- text,
- passthrough,
- NULL
-};
-
void
do_simplify (int *argc,
const char ***argv)
@@ -624,6 +693,7 @@ do_simplify (int *argc,
GOptionContext *ctx;
const GOptionEntry entries[] = {
{ "replace", 0, 0, G_OPTION_ARG_NONE, &replace, NULL, NULL },
+ { "3to4", 0, 0, G_OPTION_ARG_NONE, &data.convert3to4, NULL, NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, NULL },
{ NULL, }
};
@@ -674,19 +744,10 @@ do_simplify (int *argc,
exit (1);
}
- data.builder = gtk_builder_new ();
- data.classes = NULL;
- data.attribute_names = NULL;
- data.attribute_values = NULL;
- data.value = NULL;
- data.packing = FALSE;
- data.packing_started = FALSE;
- data.cell_packing = FALSE;
- data.cell_packing_started = FALSE;
- data.in_child = 0;
- data.child_started = 0;
- data.unclosed_starttag = FALSE;
- data.indent = 0;
+
+ data.root = NULL;
+ data.current = NULL;
+ data.value = g_string_new ("");
context = g_markup_parse_context_new (&parser, G_MARKUP_TREAT_CDATA_AS_TEXT, &data, NULL);
if (!g_markup_parse_context_parse (context, buffer, -1, &error))
@@ -695,6 +756,12 @@ do_simplify (int *argc,
exit (1);
}
+ data.builder = gtk_builder_new ();
+
+ simplify_tree (&data);
+
+ dump_tree (&data);
+
fclose (data.output);
if (data.output_filename)
diff --git a/gtk/tools/gtk-builder-tool.c b/gtk/tools/gtk-builder-tool.c
index 48b78fb08f..3219baa983 100644
--- a/gtk/tools/gtk-builder-tool.c
+++ b/gtk/tools/gtk-builder-tool.c
@@ -46,6 +46,7 @@ usage (void)
"\n"
"Simplify Options:\n"
" --replace Replace the file\n"
+ " --3to4 Convert from a GTK3 to GTK4\n"
"\n"
"Preview Options:\n"
" --id=ID Preview only the named object\n"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]