2019-02-07 09:12:09 +00:00
|
|
|
|
/* Copyright 2015 Red Hat, Inc.
|
|
|
|
|
*
|
|
|
|
|
* GTK+ is free software; you can redistribute it and/or modify it
|
|
|
|
|
* under the terms of the GNU Lesser General Public License as
|
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* GLib is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with GTK+; see the file COPYING. If not,
|
|
|
|
|
* see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*
|
|
|
|
|
* Author: Matthias Clasen
|
|
|
|
|
*/
|
|
|
|
|
|
2022-04-17 15:59:06 +00:00
|
|
|
|
#include "config.h"
|
|
|
|
|
|
2019-02-07 09:12:09 +00:00
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
|
#include <glib/gprintf.h>
|
|
|
|
|
#include <glib/gstdio.h>
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include "gtkbuilderprivate.h"
|
2020-05-18 10:04:15 +00:00
|
|
|
|
#include "gtk-builder-tool.h"
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
typedef struct Element Element;
|
|
|
|
|
struct Element {
|
|
|
|
|
Element *parent;
|
|
|
|
|
char *element_name;
|
|
|
|
|
char **attribute_names;
|
|
|
|
|
char **attribute_values;
|
|
|
|
|
char *data;
|
|
|
|
|
GList *children;
|
2019-12-13 07:05:11 +00:00
|
|
|
|
|
|
|
|
|
int line_number;
|
|
|
|
|
int char_number;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
|
|
|
|
typedef struct {
|
2019-02-07 12:12:15 +00:00
|
|
|
|
Element *root;
|
|
|
|
|
Element *current;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
GString *value;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
GtkBuilder *builder;
|
2019-02-07 17:24:49 +00:00
|
|
|
|
const char *input_filename;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
char *output_filename;
|
|
|
|
|
FILE *output;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
gboolean convert3to4;
|
2020-11-11 00:19:40 +00:00
|
|
|
|
gboolean has_gtk_requires;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
} MyParserData;
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2019-12-13 07:05:11 +00:00
|
|
|
|
g_markup_parse_context_get_position (context, &elt->line_number, &elt->char_number);
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
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
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-24 18:40:36 +00:00
|
|
|
|
static const char *
|
2019-02-07 12:12:15 +00:00
|
|
|
|
canonical_boolean_value (MyParserData *data,
|
2020-07-24 18:40:36 +00:00
|
|
|
|
const char *string)
|
2019-02-07 12:12:15 +00:00
|
|
|
|
{
|
|
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-28 16:37:45 +00:00
|
|
|
|
typedef enum {
|
|
|
|
|
PROP_KIND_OBJECT,
|
|
|
|
|
PROP_KIND_PACKING,
|
|
|
|
|
PROP_KIND_CELL_PACKING,
|
2019-05-05 17:09:17 +00:00
|
|
|
|
PROP_KIND_LAYOUT
|
2019-03-28 16:37:45 +00:00
|
|
|
|
} PropKind;
|
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
static PropKind
|
|
|
|
|
get_prop_kind (Element *element)
|
|
|
|
|
{
|
|
|
|
|
g_assert (g_str_equal (element->element_name, "property"));
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (element->parent->element_name, "packing"))
|
|
|
|
|
return PROP_KIND_PACKING;
|
|
|
|
|
else if (g_str_equal (element->parent->element_name, "layout"))
|
|
|
|
|
return PROP_KIND_LAYOUT;
|
|
|
|
|
else if (g_str_equal (element->parent->element_name, "cell-packing"))
|
|
|
|
|
return PROP_KIND_CELL_PACKING;
|
|
|
|
|
else
|
|
|
|
|
return PROP_KIND_OBJECT;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
/* 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
|
2019-02-08 15:33:11 +00:00
|
|
|
|
needs_explicit_setting (GParamSpec *pspec,
|
2019-03-28 16:37:45 +00:00
|
|
|
|
PropKind kind)
|
2019-02-07 12:12:15 +00:00
|
|
|
|
{
|
|
|
|
|
struct _Prop {
|
|
|
|
|
const char *class;
|
|
|
|
|
const char *property;
|
2019-03-28 16:37:45 +00:00
|
|
|
|
PropKind kind;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
} props[] = {
|
2019-03-28 16:37:45 +00:00
|
|
|
|
{ "GtkAboutDialog", "program-name", PROP_KIND_OBJECT },
|
|
|
|
|
{ "GtkCalendar", "year", PROP_KIND_OBJECT },
|
|
|
|
|
{ "GtkCalendar", "month", PROP_KIND_OBJECT },
|
|
|
|
|
{ "GtkCalendar", "day", PROP_KIND_OBJECT },
|
|
|
|
|
{ "GtkPlacesSidebar", "show-desktop", PROP_KIND_OBJECT },
|
|
|
|
|
{ "GtkRadioButton", "draw-indicator", PROP_KIND_OBJECT },
|
|
|
|
|
{ "GtkWidget", "hexpand", PROP_KIND_OBJECT },
|
|
|
|
|
{ "GtkWidget", "vexpand", PROP_KIND_OBJECT },
|
2020-08-02 18:13:14 +00:00
|
|
|
|
{ "GtkGridLayoutChild", "row", PROP_KIND_LAYOUT },
|
|
|
|
|
{ "GtkGridLayoutChild", "column", PROP_KIND_LAYOUT },
|
2019-02-07 12:12:15 +00:00
|
|
|
|
};
|
|
|
|
|
gboolean found;
|
2020-07-24 13:54:49 +00:00
|
|
|
|
int k;
|
2019-02-08 15:33:11 +00:00
|
|
|
|
const char *class_name;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
|
2019-02-08 15:33:11 +00:00
|
|
|
|
class_name = g_type_name (pspec->owner_type);
|
2019-02-07 12:12:15 +00:00
|
|
|
|
|
|
|
|
|
found = FALSE;
|
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (props); k++)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (class_name, props[k].class) == 0 &&
|
2019-02-08 15:33:11 +00:00
|
|
|
|
strcmp (pspec->name, props[k].property) == 0 &&
|
2019-03-28 16:37:45 +00:00
|
|
|
|
kind == props[k].kind)
|
2019-02-07 12:12:15 +00:00
|
|
|
|
{
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-13 19:03:20 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
has_attribute (Element *elt,
|
|
|
|
|
const char *name,
|
|
|
|
|
const char *value)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; elt->attribute_names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (elt->attribute_names[i], name) == 0 &&
|
|
|
|
|
(value == NULL || strcmp (elt->attribute_values[i], value) == 0))
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
is_cdata_property (Element *element)
|
|
|
|
|
{
|
|
|
|
|
if (g_str_equal (element->element_name, "property") &&
|
|
|
|
|
has_attribute (element, "name", "bytes") &&
|
|
|
|
|
element->parent != NULL &&
|
|
|
|
|
g_str_equal (element->parent->element_name, "object") &&
|
|
|
|
|
has_attribute (element->parent, "class", "GtkBuilderListItemFactory"))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
is_pcdata_element (Element *element)
|
|
|
|
|
{
|
|
|
|
|
/* elements that can contain text */
|
|
|
|
|
const char *names[] = {
|
|
|
|
|
"property",
|
|
|
|
|
"attribute",
|
|
|
|
|
"action-widget",
|
|
|
|
|
"pattern",
|
|
|
|
|
"mime-type",
|
|
|
|
|
"col",
|
|
|
|
|
"item",
|
2019-04-05 03:05:08 +00:00
|
|
|
|
"mark",
|
2021-09-29 11:48:33 +00:00
|
|
|
|
"lookup",
|
2019-02-07 12:12:15 +00:00
|
|
|
|
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",
|
2019-03-28 16:21:52 +00:00
|
|
|
|
"layout",
|
2019-02-07 12:12:15 +00:00
|
|
|
|
"cell-packing",
|
|
|
|
|
"attributes",
|
|
|
|
|
"action-widgets",
|
|
|
|
|
"patterns",
|
|
|
|
|
"mime-types",
|
|
|
|
|
"attributes",
|
|
|
|
|
"row",
|
2019-02-07 17:24:49 +00:00
|
|
|
|
"items",
|
|
|
|
|
NULL
|
2019-02-07 12:12:15 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (g_strv_contains (names, element->element_name))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 09:12:09 +00:00
|
|
|
|
static void
|
2020-07-24 18:40:36 +00:00
|
|
|
|
canonicalize_key (char *key)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2020-07-24 18:40:36 +00:00
|
|
|
|
char *p;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
|
|
|
|
for (p = key; *p != 0; p++)
|
|
|
|
|
{
|
2020-07-24 18:40:36 +00:00
|
|
|
|
char c = *p;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
|
|
|
|
/* We may meet something like AtkObject::accessible-name */
|
|
|
|
|
if (c == ':' && ((p > key && p[-1] == ':') || p[1] == ':'))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (c != '-' &&
|
|
|
|
|
(c < '0' || c > '9') &&
|
|
|
|
|
(c < 'A' || c > 'Z') &&
|
|
|
|
|
(c < 'a' || c > 'z'))
|
|
|
|
|
*p = '-';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
static struct {
|
|
|
|
|
const char *class;
|
|
|
|
|
const char *layout_manager;
|
|
|
|
|
} layout_managers[] = {
|
|
|
|
|
{ "GtkBox", "GtkBoxLayout" },
|
|
|
|
|
{ "GtkGrid", "GtkGridLayout" },
|
|
|
|
|
{ "GtkFixed", "GtkFixedLayout" },
|
|
|
|
|
{ "GtkFileChooserButton", "GtkBinLayout" },
|
|
|
|
|
{ "GtkFileChooserWidget", "GtkBinLayout" },
|
|
|
|
|
{ "GtkOverlay", "GtkOverlayLayout" }
|
|
|
|
|
};
|
|
|
|
|
|
2019-02-07 09:12:09 +00:00
|
|
|
|
static GParamSpec *
|
|
|
|
|
get_property_pspec (MyParserData *data,
|
2020-07-24 18:40:36 +00:00
|
|
|
|
const char *class_name,
|
|
|
|
|
const char *property_name,
|
2019-03-28 16:37:45 +00:00
|
|
|
|
PropKind kind)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
|
|
|
|
GType type;
|
|
|
|
|
GObjectClass *class;
|
|
|
|
|
GParamSpec *pspec;
|
2020-07-24 18:40:36 +00:00
|
|
|
|
char *canonical_name;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
|
|
|
|
type = g_type_from_name (class_name);
|
|
|
|
|
if (type == G_TYPE_INVALID)
|
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
type = gtk_builder_get_type_from_name (data->builder, class_name);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
if (type == G_TYPE_INVALID)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class = g_type_class_ref (type);
|
|
|
|
|
canonical_name = g_strdup (property_name);
|
|
|
|
|
canonicalize_key (canonical_name);
|
2019-03-28 16:37:45 +00:00
|
|
|
|
switch (kind)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-03-28 16:37:45 +00:00
|
|
|
|
case PROP_KIND_OBJECT:
|
|
|
|
|
pspec = g_object_class_find_property (class, canonical_name);
|
|
|
|
|
break;
|
2019-05-05 17:09:17 +00:00
|
|
|
|
|
2019-03-28 16:37:45 +00:00
|
|
|
|
case PROP_KIND_PACKING:
|
2019-04-05 04:02:19 +00:00
|
|
|
|
pspec = NULL;
|
2019-03-28 16:37:45 +00:00
|
|
|
|
break;
|
2019-05-05 17:09:17 +00:00
|
|
|
|
|
2019-03-28 16:37:45 +00:00
|
|
|
|
case PROP_KIND_CELL_PACKING:
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *cell_class;
|
|
|
|
|
|
2022-10-08 01:36:13 +00:00
|
|
|
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
2019-03-28 16:37:45 +00:00
|
|
|
|
/* We're just assuming that the cell layout is using a GtkCellAreaBox. */
|
|
|
|
|
cell_class = g_type_class_ref (GTK_TYPE_CELL_AREA_BOX);
|
|
|
|
|
pspec = gtk_cell_area_class_find_cell_property (GTK_CELL_AREA_CLASS (cell_class), canonical_name);
|
|
|
|
|
g_type_class_unref (cell_class);
|
2022-10-08 01:36:13 +00:00
|
|
|
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
2019-03-28 16:37:45 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2019-05-05 17:09:17 +00:00
|
|
|
|
|
|
|
|
|
case PROP_KIND_LAYOUT:
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
const char *layout_manager = NULL;
|
|
|
|
|
|
|
|
|
|
pspec = NULL;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (layout_managers); i++)
|
|
|
|
|
{
|
|
|
|
|
if (g_str_equal (layout_managers[i].class, class_name))
|
|
|
|
|
{
|
|
|
|
|
layout_manager = layout_managers[i].layout_manager;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (layout_manager)
|
|
|
|
|
{
|
|
|
|
|
GtkLayoutManagerClass *layout_manager_class;
|
|
|
|
|
|
|
|
|
|
layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (g_type_class_ref (g_type_from_name (layout_manager)));
|
|
|
|
|
if (layout_manager_class->layout_child_type != G_TYPE_INVALID)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *layout_child_class;
|
|
|
|
|
layout_child_class = g_type_class_ref (layout_manager_class->layout_child_type);
|
|
|
|
|
pspec = g_object_class_find_property (layout_child_class, canonical_name);
|
|
|
|
|
g_type_class_unref (layout_child_class);
|
|
|
|
|
}
|
|
|
|
|
g_type_class_unref (layout_manager_class);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2019-03-28 16:37:45 +00:00
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
g_free (canonical_name);
|
|
|
|
|
g_type_class_unref (class);
|
|
|
|
|
|
|
|
|
|
return pspec;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-04 15:58:11 +00:00
|
|
|
|
static const char *get_class_name (Element *element);
|
|
|
|
|
|
2019-02-07 09:12:09 +00:00
|
|
|
|
static gboolean
|
2019-05-04 15:58:11 +00:00
|
|
|
|
value_is_default (Element *element,
|
|
|
|
|
MyParserData *data,
|
2019-02-08 15:33:11 +00:00
|
|
|
|
GParamSpec *pspec,
|
2020-07-24 18:40:36 +00:00
|
|
|
|
const char *value_string)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
|
|
|
|
GValue value = { 0, };
|
|
|
|
|
gboolean ret;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
2019-02-08 15:33:11 +00:00
|
|
|
|
if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (pspec), G_TYPE_OBJECT))
|
2019-02-07 09:12:09 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
2019-12-13 18:11:59 +00:00
|
|
|
|
if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (pspec), G_TYPE_BOXED))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2021-12-13 20:08:35 +00:00
|
|
|
|
if (!value_string)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2019-02-07 09:12:09 +00:00
|
|
|
|
if (!gtk_builder_value_from_string (data->builder, pspec, value_string, &value, &error))
|
|
|
|
|
{
|
2019-12-13 07:05:11 +00:00
|
|
|
|
g_printerr (_("%s:%d: Couldn’t parse value for property '%s': %s\n"), data->input_filename, element->line_number, pspec->name, error->message);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
g_error_free (error);
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-05-04 15:58:11 +00:00
|
|
|
|
{
|
|
|
|
|
/* GtkWidget::visible has a 'smart' default */
|
|
|
|
|
if (pspec->owner_type == GTK_TYPE_WIDGET &&
|
|
|
|
|
g_str_equal (pspec->name, "visible"))
|
|
|
|
|
{
|
|
|
|
|
const char *class_name = get_class_name (element);
|
|
|
|
|
GType type = g_type_from_name (class_name);
|
|
|
|
|
gboolean default_value;
|
|
|
|
|
|
2019-05-04 15:59:08 +00:00
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_ROOT) ||
|
|
|
|
|
g_type_is_a (type, GTK_TYPE_POPOVER))
|
2019-05-04 15:58:11 +00:00
|
|
|
|
default_value = FALSE;
|
|
|
|
|
else
|
|
|
|
|
default_value = TRUE;
|
|
|
|
|
|
|
|
|
|
ret = g_value_get_boolean (&value) == default_value;
|
|
|
|
|
}
|
2020-12-05 10:44:51 +00:00
|
|
|
|
else if (pspec->owner_type == GTK_TYPE_WINDOW &&
|
|
|
|
|
(g_str_equal (pspec->name, "default-width") ||
|
|
|
|
|
g_str_equal (pspec->name, "default-height")))
|
|
|
|
|
{
|
|
|
|
|
int default_size;
|
|
|
|
|
|
|
|
|
|
default_size = g_value_get_int (&value);
|
|
|
|
|
ret = default_size <= 0;
|
|
|
|
|
}
|
2019-05-04 15:58:11 +00:00
|
|
|
|
else
|
|
|
|
|
ret = g_param_value_defaults (pspec, &value);
|
|
|
|
|
}
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
|
|
|
|
g_value_reset (&value);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-27 17:14:39 +00:00
|
|
|
|
static const char *
|
|
|
|
|
get_attribute_value (Element *element,
|
|
|
|
|
const char *name)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; element->attribute_names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (g_str_equal (element->attribute_names[i], name))
|
|
|
|
|
return element->attribute_values[i];
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-13 19:19:12 +00:00
|
|
|
|
return "";
|
2019-03-27 17:14:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-04 22:33:11 +00:00
|
|
|
|
static void
|
|
|
|
|
set_attribute_value (Element *element,
|
|
|
|
|
const char *name,
|
|
|
|
|
const char *value)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2020-11-01 19:13:49 +00:00
|
|
|
|
int len;
|
2019-04-04 22:33:11 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; element->attribute_names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (g_str_equal (element->attribute_names[i], name))
|
|
|
|
|
{
|
|
|
|
|
g_free (element->attribute_values[i]);
|
|
|
|
|
element->attribute_values[i] = g_strdup (value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-01 19:13:49 +00:00
|
|
|
|
|
|
|
|
|
len = g_strv_length (element->attribute_names);
|
2020-12-21 21:35:51 +00:00
|
|
|
|
element->attribute_names = g_realloc_n (element->attribute_names, len + 2, sizeof (char *));
|
|
|
|
|
element->attribute_values = g_realloc_n (element->attribute_values, len + 2, sizeof (char *));
|
2020-11-01 19:13:49 +00:00
|
|
|
|
element->attribute_names[len] = g_strdup (name);
|
|
|
|
|
element->attribute_values[len] = g_strdup (value);
|
|
|
|
|
element->attribute_names[len + 1] = NULL;
|
|
|
|
|
element->attribute_values[len + 1] = NULL;
|
2019-04-04 22:33:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
element_is_object_or_template (Element *element)
|
|
|
|
|
{
|
|
|
|
|
return g_str_equal (element->element_name, "object") ||
|
|
|
|
|
g_str_equal (element->element_name, "template");
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
static const char *
|
|
|
|
|
get_class_name (Element *element)
|
|
|
|
|
{
|
|
|
|
|
Element *parent = element->parent;
|
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element))
|
2019-02-07 12:12:15 +00:00
|
|
|
|
parent = element;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (parent->element_name, "packing"))
|
|
|
|
|
parent = parent->parent->parent; /* child - object */
|
2019-04-06 00:48:24 +00:00
|
|
|
|
else if (g_str_equal (parent->element_name, "layout"))
|
|
|
|
|
parent = parent->parent->parent->parent; /* object - child - object */
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
|
|
|
|
|
if (g_str_equal (parent->element_name, "object"))
|
|
|
|
|
{
|
2019-03-27 17:14:39 +00:00
|
|
|
|
return get_attribute_value (parent, "class");
|
2019-02-07 12:12:15 +00:00
|
|
|
|
}
|
|
|
|
|
else if (g_str_equal (parent->element_name, "template"))
|
|
|
|
|
{
|
2019-12-18 21:58:10 +00:00
|
|
|
|
if (get_attribute_value (parent, "parent"))
|
|
|
|
|
return get_attribute_value (parent, "parent");
|
|
|
|
|
else
|
|
|
|
|
return get_attribute_value (parent, "class");
|
2019-02-07 12:12:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-13 19:19:12 +00:00
|
|
|
|
return "";
|
2019-02-07 12:12:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 09:12:09 +00:00
|
|
|
|
static gboolean
|
2019-02-07 12:12:15 +00:00
|
|
|
|
property_is_boolean (Element *element,
|
|
|
|
|
MyParserData *data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2020-11-01 15:32:13 +00:00
|
|
|
|
GParamSpec *pspec = NULL;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
const char *class_name;
|
|
|
|
|
const char *property_name;
|
|
|
|
|
int i;
|
2019-03-28 16:37:45 +00:00
|
|
|
|
PropKind kind;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
kind = get_prop_kind (element);
|
2019-02-07 12:12:15 +00:00
|
|
|
|
class_name = get_class_name (element);
|
|
|
|
|
property_name = "";
|
|
|
|
|
|
|
|
|
|
for (i = 0; element->attribute_names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (element->attribute_names[i], "name") == 0)
|
2020-07-24 18:40:36 +00:00
|
|
|
|
property_name = (const char *)element->attribute_values[i];
|
2019-02-07 12:12:15 +00:00
|
|
|
|
}
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2020-11-01 15:32:13 +00:00
|
|
|
|
if (class_name && property_name)
|
|
|
|
|
pspec = get_property_pspec (data, class_name, property_name, kind);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
if (pspec)
|
|
|
|
|
return G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-29 01:58:29 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
property_is_enum (Element *element,
|
|
|
|
|
MyParserData *data,
|
|
|
|
|
GType *type)
|
|
|
|
|
{
|
|
|
|
|
GParamSpec *pspec = NULL;
|
|
|
|
|
const char *class_name;
|
|
|
|
|
const char *property_name;
|
|
|
|
|
int i;
|
|
|
|
|
PropKind kind;
|
|
|
|
|
|
|
|
|
|
kind = get_prop_kind (element);
|
|
|
|
|
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 char *)element->attribute_values[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (class_name && property_name)
|
|
|
|
|
pspec = get_property_pspec (data, class_name, property_name, kind);
|
|
|
|
|
if (pspec && G_TYPE_IS_ENUM (G_PARAM_SPEC_VALUE_TYPE (pspec)))
|
|
|
|
|
{
|
|
|
|
|
*type = G_PARAM_SPEC_VALUE_TYPE (pspec);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*type = G_TYPE_NONE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
canonical_enum_value (MyParserData *data,
|
|
|
|
|
GType type,
|
|
|
|
|
const char *string)
|
|
|
|
|
{
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
if (gtk_builder_value_from_string_type (data->builder, type, string, &value, NULL))
|
2021-11-21 00:51:35 +00:00
|
|
|
|
{
|
|
|
|
|
GEnumClass *eclass = g_type_class_ref (type);
|
|
|
|
|
GEnumValue *evalue = g_enum_get_value (eclass, g_value_get_enum (&value));
|
|
|
|
|
|
|
|
|
|
if (evalue)
|
|
|
|
|
return g_strdup (evalue->value_nick);
|
|
|
|
|
else
|
|
|
|
|
return g_strdup_printf ("%d", g_value_get_enum (&value));
|
|
|
|
|
}
|
2021-09-29 01:58:29 +00:00
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-18 21:58:10 +00:00
|
|
|
|
static void
|
|
|
|
|
warn_missing_property (Element *element,
|
|
|
|
|
MyParserData *data,
|
|
|
|
|
const char *class_name,
|
|
|
|
|
const char *property_name,
|
|
|
|
|
PropKind kind)
|
|
|
|
|
{
|
|
|
|
|
const char *kind_str[] = { "", "Packing ", "Cell ", "Layout " };
|
|
|
|
|
|
|
|
|
|
g_printerr (_("%s:%d: %sproperty %s::%s not found\n"),
|
|
|
|
|
data->input_filename, element->line_number, kind_str[kind], class_name, property_name);
|
|
|
|
|
}
|
2020-11-01 16:15:08 +00:00
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
property_can_be_omitted (Element *element,
|
|
|
|
|
MyParserData *data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2020-07-24 13:54:49 +00:00
|
|
|
|
int i;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
gboolean bound;
|
|
|
|
|
gboolean translatable;
|
2019-02-08 15:33:11 +00:00
|
|
|
|
const char *class_name;
|
|
|
|
|
const char *property_name;
|
|
|
|
|
const char *value_string;
|
|
|
|
|
GParamSpec *pspec;
|
2019-03-28 16:37:45 +00:00
|
|
|
|
PropKind kind;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
kind = get_prop_kind (element);
|
2019-02-07 12:12:15 +00:00
|
|
|
|
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)
|
2020-07-24 18:40:36 +00:00
|
|
|
|
property_name = (const char *)element->attribute_values[i];
|
2019-02-07 12:12:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (translatable)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (bound)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2019-03-28 16:37:45 +00:00
|
|
|
|
pspec = get_property_pspec (data, class_name, property_name, kind);
|
2019-02-08 15:33:11 +00:00
|
|
|
|
if (pspec == NULL)
|
|
|
|
|
{
|
2019-12-18 21:58:10 +00:00
|
|
|
|
warn_missing_property (element, data, class_name, property_name, kind);
|
2019-02-08 15:33:11 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-28 16:37:45 +00:00
|
|
|
|
if (needs_explicit_setting (pspec, kind))
|
2019-02-07 12:12:15 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
2019-05-04 15:58:11 +00:00
|
|
|
|
return value_is_default (element, data, pspec, value_string);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2019-02-07 12:12:15 +00:00
|
|
|
|
property_has_been_removed (Element *element,
|
|
|
|
|
MyParserData *data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2020-07-24 18:40:36 +00:00
|
|
|
|
const char *class_name;
|
|
|
|
|
const char *property_name;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
struct _Prop {
|
|
|
|
|
const char *class;
|
|
|
|
|
const char *property;
|
2019-03-28 16:37:45 +00:00
|
|
|
|
PropKind kind;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
} props[] = {
|
2019-03-28 16:37:45 +00:00
|
|
|
|
{ "GtkActionBar", "position", PROP_KIND_PACKING },
|
|
|
|
|
{ "GtkButtonBox", "secondary", PROP_KIND_PACKING },
|
|
|
|
|
{ "GtkButtonBox", "non-homogeneous", PROP_KIND_PACKING },
|
|
|
|
|
{ "GtkBox", "position", PROP_KIND_PACKING },
|
|
|
|
|
{ "GtkBox", "pack-type", PROP_KIND_PACKING },
|
|
|
|
|
{ "GtkHeaderBar", "position", PROP_KIND_PACKING },
|
|
|
|
|
{ "GtkPopoverMenu", "position",PROP_KIND_PACKING },
|
2020-12-18 23:14:24 +00:00
|
|
|
|
{ "GtkCheckButton", "draw-indicator", PROP_KIND_OBJECT },
|
2019-02-07 09:12:09 +00:00
|
|
|
|
};
|
2020-07-24 18:40:36 +00:00
|
|
|
|
char *canonical_name;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
gboolean found;
|
2020-07-24 13:54:49 +00:00
|
|
|
|
int i, k;
|
2019-03-28 16:37:45 +00:00
|
|
|
|
PropKind kind;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
kind = get_prop_kind (element);
|
2019-02-07 12:12:15 +00:00
|
|
|
|
|
|
|
|
|
class_name = get_class_name (element);
|
|
|
|
|
property_name = "";
|
|
|
|
|
|
|
|
|
|
for (i = 0; element->attribute_names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (element->attribute_names[i], "name") == 0)
|
2020-07-24 18:40:36 +00:00
|
|
|
|
property_name = (const char *)element->attribute_values[i];
|
2019-02-07 12:12:15 +00:00
|
|
|
|
}
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
|
|
|
|
canonical_name = g_strdup (property_name);
|
|
|
|
|
g_strdelimit (canonical_name, "_", '-');
|
|
|
|
|
|
|
|
|
|
found = FALSE;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (props); k++)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
|
|
|
|
if (strcmp (class_name, props[k].class) == 0 &&
|
|
|
|
|
strcmp (canonical_name, props[k].property) == 0 &&
|
2019-03-28 16:37:45 +00:00
|
|
|
|
kind == props[k].kind)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (canonical_name);
|
|
|
|
|
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-19 23:53:15 +00:00
|
|
|
|
static void
|
|
|
|
|
maybe_rename_property (Element *element, MyParserData *data)
|
|
|
|
|
{
|
2020-07-24 18:40:36 +00:00
|
|
|
|
const char *class_name;
|
|
|
|
|
const char *property_name;
|
2019-05-19 23:53:15 +00:00
|
|
|
|
struct _Prop {
|
|
|
|
|
const char *class;
|
|
|
|
|
const char *property;
|
2020-02-25 22:50:57 +00:00
|
|
|
|
GType type;
|
2019-05-19 23:53:15 +00:00
|
|
|
|
PropKind kind;
|
|
|
|
|
const char *new_name;
|
2020-02-25 22:50:57 +00:00
|
|
|
|
const char *alt_names[3];
|
2019-05-19 23:53:15 +00:00
|
|
|
|
} props[] = {
|
2020-04-12 15:32:40 +00:00
|
|
|
|
/* the "replacement" property is placed *after* the "added" properties */
|
2020-02-25 22:50:57 +00:00
|
|
|
|
{ "GtkPopover", "modal", GTK_TYPE_POPOVER, PROP_KIND_OBJECT, "autohide", { NULL, NULL, NULL } },
|
2020-04-12 15:32:40 +00:00
|
|
|
|
{ "GtkWidget", "expand", GTK_TYPE_WIDGET, PROP_KIND_OBJECT, "vexpand", { "hexpand", NULL, NULL } },
|
|
|
|
|
{ "GtkWidget", "margin", GTK_TYPE_WIDGET, PROP_KIND_OBJECT, "margin-bottom", { "margin-start", "margin-end", "margin-top" } },
|
2020-04-12 16:40:14 +00:00
|
|
|
|
{ "GtkWidget", "margin-left", GTK_TYPE_WIDGET, PROP_KIND_OBJECT, "margin-start", { NULL, NULL, NULL } },
|
|
|
|
|
{ "GtkWidget", "margin-right", GTK_TYPE_WIDGET, PROP_KIND_OBJECT, "margin-end", { NULL, NULL, NULL } },
|
2020-04-28 23:59:13 +00:00
|
|
|
|
{ "GtkHeaderBar", "show-close-button", GTK_TYPE_HEADER_BAR, PROP_KIND_OBJECT, "show-title-buttons", { NULL, NULL, NULL } },
|
2020-05-01 13:48:03 +00:00
|
|
|
|
{ "GtkHeaderBar", "custom-title", GTK_TYPE_HEADER_BAR, PROP_KIND_OBJECT, "title-widget", { NULL, NULL, NULL } },
|
2021-01-27 22:01:51 +00:00
|
|
|
|
{ "GtkStack", "homogeneous", GTK_TYPE_STACK, PROP_KIND_OBJECT, "hhomogeneous", { "vhomogeneous", NULL, NULL } },
|
|
|
|
|
{ "GtkImage", "pixbuf", GTK_TYPE_IMAGE, PROP_KIND_OBJECT, "file", { NULL, NULL, NULL } },
|
2021-06-05 21:56:35 +00:00
|
|
|
|
{ "GtkWidget", "can-focus", GTK_TYPE_WIDGET, PROP_KIND_OBJECT, "focusable", { NULL, NULL, NULL } },
|
2019-05-19 23:53:15 +00:00
|
|
|
|
};
|
2020-02-25 22:50:57 +00:00
|
|
|
|
int i, k, l;
|
2019-05-19 23:53:15 +00:00
|
|
|
|
PropKind kind;
|
|
|
|
|
int prop_name_index = 0;
|
2020-02-26 14:59:14 +00:00
|
|
|
|
GType type;
|
|
|
|
|
char *canonical_name;
|
2019-05-19 23:53:15 +00:00
|
|
|
|
|
|
|
|
|
kind = get_prop_kind (element);
|
|
|
|
|
|
|
|
|
|
class_name = get_class_name (element);
|
|
|
|
|
property_name = NULL;
|
|
|
|
|
|
|
|
|
|
for (i = 0; element->attribute_names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (element->attribute_names[i], "name") == 0)
|
|
|
|
|
{
|
|
|
|
|
prop_name_index = i;
|
2020-07-24 18:40:36 +00:00
|
|
|
|
property_name = (const char *)element->attribute_values[i];
|
2019-05-19 23:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (property_name == NULL)
|
|
|
|
|
return;
|
2020-04-12 19:21:24 +00:00
|
|
|
|
|
2020-02-26 14:59:14 +00:00
|
|
|
|
type = g_type_from_name (class_name);
|
2019-05-19 23:53:15 +00:00
|
|
|
|
|
2020-02-26 14:59:14 +00:00
|
|
|
|
canonical_name = g_strdup (property_name);
|
|
|
|
|
g_strdelimit (canonical_name, "_", '-');
|
2020-04-12 19:21:24 +00:00
|
|
|
|
|
2019-05-19 23:53:15 +00:00
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (props); k++)
|
|
|
|
|
{
|
2020-02-26 14:59:14 +00:00
|
|
|
|
if (g_type_is_a (type, props[k].type) &&
|
|
|
|
|
strcmp (canonical_name, props[k].property) == 0 &&
|
2019-05-19 23:53:15 +00:00
|
|
|
|
kind == props[k].kind)
|
|
|
|
|
{
|
|
|
|
|
g_free (element->attribute_values[prop_name_index]);
|
|
|
|
|
element->attribute_values[prop_name_index] = g_strdup (props[k].new_name);
|
2020-02-25 22:50:57 +00:00
|
|
|
|
for (l = 0; l < 3 && props[k].alt_names[l]; l++)
|
|
|
|
|
{
|
|
|
|
|
Element *elt;
|
|
|
|
|
GList *sibling;
|
|
|
|
|
|
|
|
|
|
elt = g_new0 (Element, 1);
|
|
|
|
|
elt->parent = element->parent;
|
|
|
|
|
elt->element_name = g_strdup (element->element_name);
|
2020-02-26 01:57:20 +00:00
|
|
|
|
elt->attribute_names = g_strdupv ((char **) element->attribute_names);
|
|
|
|
|
elt->attribute_values = g_strdupv ((char **) element->attribute_values);
|
2020-02-25 22:50:57 +00:00
|
|
|
|
elt->data = g_strdup (element->data);
|
|
|
|
|
|
|
|
|
|
g_free (elt->attribute_values[prop_name_index]);
|
|
|
|
|
elt->attribute_values[prop_name_index] = g_strdup (props[k].alt_names[l]);
|
|
|
|
|
|
|
|
|
|
sibling = g_list_find (element->parent->children, element);
|
|
|
|
|
element->parent->children = g_list_insert_before (element->parent->children,
|
|
|
|
|
sibling,
|
|
|
|
|
elt);
|
|
|
|
|
}
|
2019-05-19 23:53:15 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-26 14:59:14 +00:00
|
|
|
|
|
|
|
|
|
g_free (canonical_name);
|
2019-05-19 23:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
static Element *
|
|
|
|
|
rewrite_stack_child (Element *child, MyParserData *data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
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;
|
2019-08-26 13:34:15 +00:00
|
|
|
|
new_object->parent = child;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
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);
|
2019-08-26 13:34:15 +00:00
|
|
|
|
prop->parent = new_object;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
new_object->children = g_list_append (new_object->children, prop);
|
2020-04-12 19:21:24 +00:00
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
g_list_free (child->children);
|
|
|
|
|
child->children = g_list_append (NULL, new_object);
|
|
|
|
|
|
|
|
|
|
return child;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2019-02-07 12:12:15 +00:00
|
|
|
|
rewrite_stack (Element *element,
|
|
|
|
|
MyParserData *data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
GList *l, *new_children;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
new_children = NULL;
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
Element *child = l->data;
|
|
|
|
|
new_children = g_list_append (new_children, rewrite_stack_child (child, data));
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
2019-02-07 12:12:15 +00:00
|
|
|
|
|
|
|
|
|
g_list_free (element->children);
|
|
|
|
|
element->children = new_children;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 20:34:54 +00:00
|
|
|
|
static Element *
|
|
|
|
|
rewrite_assistant_child (Element *child, MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
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 ("GtkAssistantPage");
|
|
|
|
|
new_object->children = packing->children;
|
2019-05-30 09:29:50 +00:00
|
|
|
|
new_object->parent = child;
|
2019-02-07 20:34:54 +00:00
|
|
|
|
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);
|
2019-05-30 09:29:50 +00:00
|
|
|
|
prop->parent = new_object;
|
2019-02-07 20:34:54 +00:00
|
|
|
|
new_object->children = g_list_append (new_object->children, prop);
|
2020-04-12 19:21:24 +00:00
|
|
|
|
|
2019-02-07 20:34:54 +00:00
|
|
|
|
g_list_free (child->children);
|
|
|
|
|
child->children = g_list_append (NULL, new_object);
|
|
|
|
|
|
|
|
|
|
return child;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rewrite_assistant (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l, *new_children;
|
|
|
|
|
|
|
|
|
|
new_children = NULL;
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
new_children = g_list_append (new_children, rewrite_assistant_child (child, data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_list_free (element->children);
|
|
|
|
|
element->children = new_children;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-21 03:48:58 +00:00
|
|
|
|
static Element *
|
|
|
|
|
rewrite_notebook_page (Element *child, Element *tab, MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
Element *object = NULL;
|
|
|
|
|
Element *tab_obj = NULL;
|
|
|
|
|
Element *packing = NULL;
|
|
|
|
|
Element *new_object;
|
|
|
|
|
Element *prop;
|
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
|
|
if (!g_str_equal (child->element_name, "child"))
|
|
|
|
|
return child;
|
|
|
|
|
|
|
|
|
|
if (has_attribute (child, "type", "tab") ||
|
|
|
|
|
has_attribute (child, "type", "action-start") ||
|
|
|
|
|
has_attribute (child, "type", "action-end"))
|
|
|
|
|
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;
|
2021-03-23 19:24:30 +00:00
|
|
|
|
else if (g_str_equal (elt->element_name, "placeholder"))
|
|
|
|
|
return child;
|
2019-02-21 03:48:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!packing && !tab)
|
|
|
|
|
return child;
|
|
|
|
|
|
|
|
|
|
if (tab)
|
|
|
|
|
{
|
|
|
|
|
for (l = tab->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = l->data;
|
|
|
|
|
if (g_str_equal (elt->element_name, "object"))
|
|
|
|
|
tab_obj = elt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 ("GtkNotebookPage");
|
2019-08-26 13:34:15 +00:00
|
|
|
|
new_object->parent = child;
|
2019-02-21 03:48:58 +00:00
|
|
|
|
if (packing)
|
|
|
|
|
{
|
|
|
|
|
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);
|
2019-08-26 13:34:15 +00:00
|
|
|
|
prop->parent = new_object;
|
2019-02-21 03:48:58 +00:00
|
|
|
|
new_object->children = g_list_append (new_object->children, prop);
|
|
|
|
|
|
|
|
|
|
if (tab_obj)
|
|
|
|
|
{
|
|
|
|
|
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 ("tab");
|
|
|
|
|
prop->children = g_list_append (prop->children, tab_obj);
|
2019-08-26 13:34:15 +00:00
|
|
|
|
prop->parent = new_object;
|
2019-02-21 03:48:58 +00:00
|
|
|
|
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
|
|
|
|
|
rewrite_notebook (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l, *new_children;
|
|
|
|
|
|
|
|
|
|
new_children = NULL;
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
Element *tab = l->next ? l->next->data : NULL;
|
|
|
|
|
|
|
|
|
|
if (tab && has_attribute (tab, "type", "tab"))
|
|
|
|
|
{
|
|
|
|
|
new_children = g_list_append (new_children, rewrite_notebook_page (child, tab, data));
|
|
|
|
|
l = l->next; /* skip the tab */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
new_children = g_list_append (new_children, rewrite_notebook_page (child, NULL, data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_list_free (element->children);
|
|
|
|
|
element->children = new_children;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-27 17:14:39 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_pack_type_child (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
Element *pack_type = NULL;
|
|
|
|
|
GList *l, *ll;
|
|
|
|
|
|
|
|
|
|
if (!g_str_equal (element->element_name, "child"))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt->element_name, "packing"))
|
|
|
|
|
{
|
|
|
|
|
for (ll = elt->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "property") &&
|
|
|
|
|
has_attribute (elt2, "name", "pack-type"))
|
|
|
|
|
{
|
|
|
|
|
pack_type = elt2;
|
|
|
|
|
elt->children = g_list_remove (elt->children, pack_type);
|
2019-03-27 22:38:29 +00:00
|
|
|
|
if (elt->children == NULL)
|
|
|
|
|
{
|
|
|
|
|
element->children = g_list_remove (element->children, elt);
|
|
|
|
|
free_element (elt);
|
|
|
|
|
}
|
2019-03-27 17:14:39 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-27 22:38:29 +00:00
|
|
|
|
|
|
|
|
|
if (pack_type)
|
|
|
|
|
break;
|
2019-03-27 17:14:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pack_type)
|
|
|
|
|
{
|
|
|
|
|
char **attnames = g_new0 (char *, g_strv_length (element->attribute_names) + 2);
|
|
|
|
|
char **attvalues = g_new0 (char *, g_strv_length (element->attribute_names) + 2);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; element->attribute_names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
attnames[i] = g_strdup (element->attribute_names[i]);
|
|
|
|
|
attvalues[i] = g_strdup (element->attribute_values[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attnames[i] = g_strdup ("type");
|
|
|
|
|
attvalues[i] = g_strdup (pack_type->data);
|
|
|
|
|
|
|
|
|
|
g_strfreev (element->attribute_names);
|
|
|
|
|
g_strfreev (element->attribute_values);
|
|
|
|
|
|
|
|
|
|
element->attribute_names = attnames;
|
|
|
|
|
element->attribute_values = attvalues;
|
|
|
|
|
|
|
|
|
|
free_element (pack_type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rewrite_pack_type (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = l->data;
|
|
|
|
|
if (g_str_equal (elt->element_name, "child"))
|
2020-04-12 19:21:24 +00:00
|
|
|
|
rewrite_pack_type_child (elt, data);
|
2019-03-27 17:14:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-28 01:23:56 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_paned_child (Element *element,
|
|
|
|
|
MyParserData *data,
|
|
|
|
|
Element *child,
|
|
|
|
|
const char *suffix)
|
|
|
|
|
{
|
|
|
|
|
Element *resize = NULL;
|
|
|
|
|
Element *shrink = NULL;
|
|
|
|
|
GList *l, *ll;
|
|
|
|
|
|
|
|
|
|
for (l = child->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt->element_name, "packing"))
|
|
|
|
|
{
|
|
|
|
|
for (ll = elt->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "property") &&
|
|
|
|
|
has_attribute (elt2, "name", "resize"))
|
|
|
|
|
resize = elt2;
|
2020-03-06 04:29:46 +00:00
|
|
|
|
else if (g_str_equal (elt2->element_name, "property") &&
|
2019-03-28 01:23:56 +00:00
|
|
|
|
has_attribute (elt2, "name", "shrink"))
|
|
|
|
|
shrink = elt2;
|
|
|
|
|
}
|
|
|
|
|
if (resize)
|
|
|
|
|
elt->children = g_list_remove (elt->children, resize);
|
|
|
|
|
if (shrink)
|
|
|
|
|
elt->children = g_list_remove (elt->children, shrink);
|
|
|
|
|
if (elt->children == NULL)
|
|
|
|
|
{
|
|
|
|
|
child->children = g_list_remove (child->children, elt);
|
|
|
|
|
free_element (elt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (resize || shrink)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (resize)
|
|
|
|
|
{
|
|
|
|
|
Element *elt;
|
|
|
|
|
|
|
|
|
|
elt = g_new0 (Element, 1);
|
|
|
|
|
elt->parent = element;
|
|
|
|
|
elt->element_name = g_strdup ("property");
|
|
|
|
|
elt->attribute_names = g_new0 (char *, 2);
|
|
|
|
|
elt->attribute_names[0] = g_strdup ("name");
|
|
|
|
|
elt->attribute_values = g_new0 (char *, 2);
|
|
|
|
|
elt->attribute_values[0] = g_strconcat ("resize-", suffix, NULL);
|
|
|
|
|
elt->data = g_strdup (resize->data);
|
|
|
|
|
|
|
|
|
|
element->children = g_list_prepend (element->children, elt);
|
|
|
|
|
|
|
|
|
|
free_element (resize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (shrink)
|
|
|
|
|
{
|
|
|
|
|
Element *elt;
|
|
|
|
|
|
|
|
|
|
elt = g_new0 (Element, 1);
|
|
|
|
|
elt->parent = element;
|
|
|
|
|
elt->element_name = g_strdup ("property");
|
|
|
|
|
elt->attribute_names = g_new0 (char *, 2);
|
|
|
|
|
elt->attribute_names[0] = g_strdup ("name");
|
|
|
|
|
elt->attribute_values = g_new0 (char *, 2);
|
|
|
|
|
elt->attribute_values[0] = g_strconcat ("shrink-", suffix, NULL);
|
|
|
|
|
elt->data = g_strdup (shrink->data);
|
|
|
|
|
|
|
|
|
|
element->children = g_list_prepend (element->children, elt);
|
|
|
|
|
|
|
|
|
|
free_element (shrink);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rewrite_paned (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
Element *child1 = NULL;
|
|
|
|
|
Element *child2 = NULL;
|
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt->element_name, "child"))
|
|
|
|
|
{
|
|
|
|
|
if (child1 == NULL)
|
|
|
|
|
child1 = elt;
|
|
|
|
|
else if (child2 == NULL)
|
|
|
|
|
child2 = elt;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (child1)
|
2020-11-01 16:37:16 +00:00
|
|
|
|
rewrite_paned_child (element, data, child1, "start-child");
|
2019-03-28 01:23:56 +00:00
|
|
|
|
|
|
|
|
|
if (child2)
|
2020-11-01 16:37:16 +00:00
|
|
|
|
rewrite_paned_child (element, data, child2, "end-child");
|
2019-03-28 01:23:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-30 07:44:44 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_dialog (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
Element *content_area = NULL;
|
|
|
|
|
Element *vbox = NULL;
|
|
|
|
|
Element *action_area = NULL;
|
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt->element_name, "child") &&
|
|
|
|
|
g_strcmp0 (get_attribute_value (elt, "internal-child"), "vbox") == 0)
|
|
|
|
|
{
|
|
|
|
|
content_area = elt;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!content_area || !content_area->children)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
vbox = content_area->children->data;
|
|
|
|
|
|
|
|
|
|
for (l = vbox->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt->element_name, "child") &&
|
|
|
|
|
g_strcmp0 (get_attribute_value (elt, "internal-child"), "action_area") == 0)
|
|
|
|
|
{
|
|
|
|
|
action_area = elt;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!action_area)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
set_attribute_value (content_area, "internal-child", "content_area");
|
|
|
|
|
vbox->children = g_list_remove (vbox->children, action_area);
|
|
|
|
|
action_area->parent = element;
|
|
|
|
|
element->children = g_list_append (element->children, action_area);
|
|
|
|
|
|
|
|
|
|
for (l = action_area->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt->element_name, "packing"))
|
|
|
|
|
{
|
|
|
|
|
action_area->children = g_list_remove (action_area->children, elt);
|
|
|
|
|
free_element (elt);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-04 22:33:11 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_grid_layout_prop (Element *element,
|
|
|
|
|
const char *attr_name,
|
|
|
|
|
const char *old_value,
|
|
|
|
|
const char *new_value)
|
|
|
|
|
{
|
|
|
|
|
if (g_str_equal (element->element_name, "property"))
|
|
|
|
|
{
|
2020-08-02 19:10:18 +00:00
|
|
|
|
char *canonical_name;
|
|
|
|
|
|
|
|
|
|
canonical_name = g_strdup (old_value);
|
|
|
|
|
g_strdelimit (canonical_name, "_", '-');
|
|
|
|
|
|
2019-04-04 22:33:11 +00:00
|
|
|
|
if (has_attribute (element, attr_name, old_value) ||
|
|
|
|
|
has_attribute (element, attr_name, canonical_name))
|
|
|
|
|
{
|
|
|
|
|
set_attribute_value (element, attr_name, new_value);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-02 19:10:18 +00:00
|
|
|
|
g_free (canonical_name);
|
|
|
|
|
}
|
2019-04-04 22:33:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rewrite_grid_layout (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
struct _Prop {
|
|
|
|
|
const char *attr_name;
|
|
|
|
|
const char *old_value;
|
|
|
|
|
const char *new_value;
|
|
|
|
|
} props[] = {
|
2020-08-02 19:10:18 +00:00
|
|
|
|
{ "name", "left_attach", "column", },
|
|
|
|
|
{ "name", "top_attach", "row", },
|
2019-04-04 22:33:11 +00:00
|
|
|
|
{ "name", "width", "column-span", },
|
|
|
|
|
{ "name", "height", "row-span", },
|
|
|
|
|
};
|
|
|
|
|
GList *l, *ll;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (child->element_name, "child"))
|
|
|
|
|
{
|
|
|
|
|
Element *object = NULL;
|
|
|
|
|
Element *packing = NULL;
|
|
|
|
|
|
|
|
|
|
for (ll = child->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "object"))
|
|
|
|
|
object = elt2;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "packing"))
|
|
|
|
|
packing = elt2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (object && packing)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
child->children = g_list_remove (child->children, packing);
|
|
|
|
|
|
|
|
|
|
g_free (packing->element_name);
|
|
|
|
|
packing->element_name = g_strdup ("layout");
|
|
|
|
|
|
|
|
|
|
packing->parent = object;
|
|
|
|
|
object->children = g_list_append (object->children, packing);
|
|
|
|
|
|
|
|
|
|
for (ll = packing->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = ll->data;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (props); i++)
|
|
|
|
|
rewrite_grid_layout_prop (elt,
|
|
|
|
|
props[i].attr_name,
|
|
|
|
|
props[i].old_value,
|
|
|
|
|
props[i].new_value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 19:13:49 +00:00
|
|
|
|
static Element *
|
|
|
|
|
add_element (Element *parent,
|
|
|
|
|
const char *element_name)
|
|
|
|
|
{
|
|
|
|
|
Element *child;
|
|
|
|
|
|
|
|
|
|
child = g_new0 (Element, 1);
|
|
|
|
|
child->parent = parent;
|
|
|
|
|
child->element_name = g_strdup (element_name);
|
|
|
|
|
child->attribute_names = g_new0 (char *, 1);
|
|
|
|
|
child->attribute_values = g_new0 (char *, 1);
|
|
|
|
|
parent->children = g_list_prepend (parent->children, child);
|
|
|
|
|
|
|
|
|
|
return child;
|
|
|
|
|
}
|
2020-08-17 01:32:21 +00:00
|
|
|
|
|
|
|
|
|
static Element *
|
|
|
|
|
write_box_prop (Element *element,
|
|
|
|
|
Element *parent,
|
|
|
|
|
const char *name,
|
|
|
|
|
const char *value)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (element)
|
|
|
|
|
g_free (element->data);
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-11-01 19:13:49 +00:00
|
|
|
|
element = add_element (parent, "property");
|
|
|
|
|
set_attribute_value (element, "name", name);
|
2020-08-17 01:32:21 +00:00
|
|
|
|
}
|
|
|
|
|
element->data = g_strdup (value);
|
2020-11-01 19:13:49 +00:00
|
|
|
|
|
2020-08-17 01:32:21 +00:00
|
|
|
|
return element;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rewrite_box (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l, *ll;
|
|
|
|
|
GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (get_class_name (element), "GtkVBox"))
|
|
|
|
|
write_box_prop (NULL, element, "orientation", "vertical");
|
|
|
|
|
|
|
|
|
|
if (!g_str_equal (get_class_name (element), "GtkBox"))
|
|
|
|
|
set_attribute_value (element, "class", "GtkBox");
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (child->element_name, "property"))
|
|
|
|
|
{
|
|
|
|
|
if (has_attribute (child, "name", "orientation"))
|
|
|
|
|
{
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
if (gtk_builder_value_from_string_type (data->builder,
|
|
|
|
|
GTK_TYPE_ORIENTATION,
|
|
|
|
|
child->data,
|
|
|
|
|
&value,
|
|
|
|
|
NULL))
|
|
|
|
|
orientation = g_value_get_enum (&value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
if (g_str_equal (child->element_name, "child"))
|
|
|
|
|
{
|
|
|
|
|
Element *object = NULL;
|
|
|
|
|
Element *packing = NULL;
|
|
|
|
|
|
|
|
|
|
for (ll = child->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "object"))
|
|
|
|
|
object = elt2;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "packing"))
|
|
|
|
|
packing = elt2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (object && packing)
|
|
|
|
|
{
|
|
|
|
|
Element *halign = NULL;
|
|
|
|
|
Element *hexpand = NULL;
|
|
|
|
|
Element *valign = NULL;
|
|
|
|
|
Element *vexpand = NULL;
|
|
|
|
|
|
|
|
|
|
gboolean expand = FALSE;
|
|
|
|
|
gboolean fill = TRUE;
|
|
|
|
|
|
|
|
|
|
for (ll = object->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = ll->data;
|
|
|
|
|
if (g_str_equal (elt->element_name, "property"))
|
|
|
|
|
{
|
|
|
|
|
if (has_attribute (elt, "name", "halign"))
|
|
|
|
|
halign = elt;
|
|
|
|
|
else if (has_attribute (elt, "name", "hexpand"))
|
|
|
|
|
hexpand = elt;
|
|
|
|
|
else if (has_attribute (elt, "name", "valign"))
|
|
|
|
|
valign = elt;
|
|
|
|
|
else if (has_attribute (elt, "name", "vexpand"))
|
|
|
|
|
vexpand = elt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (ll = packing->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt = ll->data;
|
|
|
|
|
|
|
|
|
|
if (has_attribute (elt, "name", "expand"))
|
|
|
|
|
{
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
if (gtk_builder_value_from_string_type (data->builder,
|
|
|
|
|
G_TYPE_BOOLEAN,
|
|
|
|
|
elt->data,
|
|
|
|
|
&value,
|
|
|
|
|
NULL))
|
|
|
|
|
expand = g_value_get_boolean (&value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (has_attribute (elt, "name", "fill"))
|
|
|
|
|
{
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
if (gtk_builder_value_from_string_type (data->builder,
|
|
|
|
|
G_TYPE_BOOLEAN,
|
|
|
|
|
elt->data,
|
|
|
|
|
&value,
|
|
|
|
|
NULL))
|
|
|
|
|
fill = g_value_get_boolean (&value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
|
|
|
|
{
|
|
|
|
|
if (expand)
|
2021-05-03 11:36:19 +00:00
|
|
|
|
write_box_prop (hexpand, object, "hexpand", "1");
|
2020-08-17 01:32:21 +00:00
|
|
|
|
if (!fill)
|
2021-05-03 11:36:19 +00:00
|
|
|
|
write_box_prop (halign, object, "halign", "center");
|
2020-08-17 01:32:21 +00:00
|
|
|
|
}
|
|
|
|
|
else if (orientation == GTK_ORIENTATION_VERTICAL)
|
|
|
|
|
{
|
|
|
|
|
if (expand)
|
2021-05-03 11:36:19 +00:00
|
|
|
|
write_box_prop (vexpand, object, "vexpand", "1");
|
2020-08-17 01:32:21 +00:00
|
|
|
|
if (!fill)
|
2021-05-03 11:36:19 +00:00
|
|
|
|
write_box_prop (valign, object, "valign", "center");
|
2020-08-17 01:32:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
child->children = g_list_remove (child->children, packing);
|
|
|
|
|
free_element (packing);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-01 22:02:46 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_bin_child (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l, *ll;
|
|
|
|
|
const char *class_name;
|
|
|
|
|
GType type;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
Element *object = NULL;
|
|
|
|
|
|
|
|
|
|
if (!g_str_equal (child->element_name, "child") ||
|
|
|
|
|
has_attribute (child, "type", NULL))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (ll = child->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elem = ll->data;
|
|
|
|
|
|
|
|
|
|
if (!g_str_equal (elem->element_name, "object"))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
class_name = get_attribute_value (elem, "class");
|
|
|
|
|
if (!class_name)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
type = g_type_from_name (class_name);
|
|
|
|
|
if (!g_type_is_a (type, GTK_TYPE_WIDGET))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
object = elem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (object)
|
|
|
|
|
{
|
|
|
|
|
g_free (child->element_name);
|
|
|
|
|
g_strfreev (child->attribute_names);
|
|
|
|
|
g_strfreev (child->attribute_values);
|
|
|
|
|
child->element_name = g_strdup ("property");
|
|
|
|
|
child->attribute_names = g_new0 (char *, 2);
|
|
|
|
|
child->attribute_names[0] = g_strdup ("name");
|
|
|
|
|
child->attribute_values = g_new0 (char *, 2);
|
|
|
|
|
child->attribute_values[0] = g_strdup ("child");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-31 01:07:20 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
remove_boolean_prop (Element *element,
|
|
|
|
|
MyParserData *data,
|
|
|
|
|
const char *prop_name,
|
|
|
|
|
gboolean *value)
|
|
|
|
|
{
|
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (child->element_name, "property") &&
|
|
|
|
|
has_attribute (child, "name", prop_name))
|
|
|
|
|
{
|
|
|
|
|
*value = strcmp (canonical_boolean_value (data, child->data), "1") == 0;
|
|
|
|
|
element->children = g_list_remove (element->children, child);
|
|
|
|
|
free_element (child);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rewrite_radio_button (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
gboolean draw_indicator = TRUE;
|
|
|
|
|
|
|
|
|
|
if (!remove_boolean_prop (element, data, "draw-indicator", &draw_indicator))
|
|
|
|
|
remove_boolean_prop (element, data, "draw_indicator", &draw_indicator);
|
|
|
|
|
|
|
|
|
|
if (draw_indicator)
|
2020-11-01 19:13:49 +00:00
|
|
|
|
set_attribute_value (element, "class", "GtkCheckButton");
|
2020-08-31 01:07:20 +00:00
|
|
|
|
else
|
2020-11-01 19:13:49 +00:00
|
|
|
|
set_attribute_value (element, "class", "GtkToggleButton");
|
2020-08-31 01:07:20 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-04 00:08:29 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
has_prop (Element *element,
|
|
|
|
|
MyParserData *data,
|
|
|
|
|
const char *prop_name)
|
|
|
|
|
{
|
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (child->element_name, "property") &&
|
|
|
|
|
has_attribute (child, "name", prop_name))
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rewrite_scale (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
if (!has_prop (element, data, "draw-value") &&
|
|
|
|
|
!has_prop (element, data, "draw_value"))
|
|
|
|
|
{
|
|
|
|
|
Element *child;
|
2020-11-01 19:13:49 +00:00
|
|
|
|
child = add_element (element, "property");
|
|
|
|
|
set_attribute_value (child, "name", "draw-value");
|
2020-10-04 00:08:29 +00:00
|
|
|
|
child->data = g_strdup ("1");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-07 10:24:19 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_requires (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
if (has_attribute (element, "lib", "gtk+"))
|
2020-11-11 00:19:40 +00:00
|
|
|
|
{
|
|
|
|
|
set_attribute_value (element, "lib", "gtk");
|
|
|
|
|
set_attribute_value (element, "version", "4.0");
|
|
|
|
|
}
|
2020-11-07 10:24:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 16:14:03 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_overlay (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l, *ll;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (child->element_name, "child"))
|
|
|
|
|
{
|
|
|
|
|
Element *object = NULL;
|
|
|
|
|
Element *packing = NULL;
|
|
|
|
|
|
|
|
|
|
for (ll = child->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "object"))
|
|
|
|
|
object = elt2;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "packing"))
|
|
|
|
|
packing = elt2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (object && packing)
|
|
|
|
|
{
|
|
|
|
|
child->children = g_list_remove (child->children, packing);
|
|
|
|
|
|
|
|
|
|
for (ll = packing->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "property") &&
|
|
|
|
|
(has_attribute (elt2, "name", "pass-through") ||
|
|
|
|
|
has_attribute (elt2, "name", "pass_through")))
|
|
|
|
|
{
|
|
|
|
|
const char *b = canonical_boolean_value (data, elt2->data);
|
|
|
|
|
if (g_str_equal (b, "1"))
|
|
|
|
|
{
|
2020-11-01 19:13:49 +00:00
|
|
|
|
Element *new_prop;
|
|
|
|
|
|
|
|
|
|
new_prop = add_element (object, "property");
|
|
|
|
|
set_attribute_value (new_prop, "name", "can-target");
|
2020-11-01 16:14:03 +00:00
|
|
|
|
new_prop->data = g_strdup ("0");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free_element (packing);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 19:13:49 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_toolbar (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l, *ll;
|
|
|
|
|
|
|
|
|
|
set_attribute_value (element, "class", "GtkBox");
|
|
|
|
|
|
2021-01-05 18:57:47 +00:00
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (child->element_name, "property") &&
|
|
|
|
|
(has_attribute (child, "name", "toolbar_style") ||
|
|
|
|
|
has_attribute (child, "name", "toolbar-style")))
|
|
|
|
|
{
|
|
|
|
|
element->children = g_list_remove (element->children, child);
|
|
|
|
|
free_element (child);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 19:13:49 +00:00
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
Element *object = NULL;
|
|
|
|
|
Element *packing = NULL;
|
|
|
|
|
|
|
|
|
|
if (!g_str_equal (child->element_name, "child"))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (ll = child->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "object"))
|
|
|
|
|
object = elt2;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "packing"))
|
|
|
|
|
packing = elt2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (object)
|
|
|
|
|
{
|
|
|
|
|
const char *class_name;
|
|
|
|
|
|
|
|
|
|
class_name = get_class_name (object);
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (class_name, "GtkToolButton"))
|
|
|
|
|
{
|
|
|
|
|
set_attribute_value (object, "class", "GtkButton");
|
|
|
|
|
}
|
|
|
|
|
else if (g_str_equal (class_name, "GtkToggleToolButton") ||
|
|
|
|
|
g_str_equal (class_name, "GtkRadioToolButton"))
|
|
|
|
|
{
|
|
|
|
|
set_attribute_value (object, "class", "GtkToggleButton");
|
|
|
|
|
}
|
|
|
|
|
else if (g_str_equal (class_name, "GtkSeparatorToolItem"))
|
|
|
|
|
{
|
|
|
|
|
Element *prop;
|
|
|
|
|
|
|
|
|
|
set_attribute_value (object, "class", "GtkSeparator");
|
|
|
|
|
prop = add_element (object, "property");
|
|
|
|
|
set_attribute_value (prop, "name", "orientation");
|
|
|
|
|
prop->data = g_strdup ("vertical");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (packing)
|
|
|
|
|
child->children = g_list_remove (child->children, packing);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-28 19:59:24 +00:00
|
|
|
|
{
|
|
|
|
|
Element *child;
|
2020-11-01 19:13:49 +00:00
|
|
|
|
|
2021-09-28 19:59:24 +00:00
|
|
|
|
child = add_element (element, "property");
|
|
|
|
|
set_attribute_value (child, "name", "css-classes");
|
|
|
|
|
child->data = g_strdup ("toolbar");
|
|
|
|
|
}
|
2020-11-01 19:13:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 21:51:14 +00:00
|
|
|
|
static void
|
|
|
|
|
rewrite_fixed (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l, *ll;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (child->element_name, "child"))
|
|
|
|
|
{
|
|
|
|
|
Element *object = NULL;
|
|
|
|
|
Element *packing = NULL;
|
|
|
|
|
|
|
|
|
|
for (ll = child->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "object"))
|
|
|
|
|
object = elt2;
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (elt2->element_name, "packing"))
|
|
|
|
|
packing = elt2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (object && packing)
|
|
|
|
|
{
|
|
|
|
|
int x = 0;
|
|
|
|
|
int y = 0;
|
|
|
|
|
Element *layout;
|
|
|
|
|
Element *new_prop;
|
|
|
|
|
GskTransform *transform;
|
|
|
|
|
|
|
|
|
|
for (ll = packing->children; ll; ll = ll->next)
|
|
|
|
|
{
|
|
|
|
|
Element *elt2 = ll->data;
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
if (has_attribute (elt2, "name", "x"))
|
|
|
|
|
{
|
|
|
|
|
if (gtk_builder_value_from_string_type (data->builder, G_TYPE_INT, elt2->data, &value, NULL))
|
|
|
|
|
x = g_value_get_int (&value);
|
|
|
|
|
}
|
|
|
|
|
else if (has_attribute (elt2, "name", "y"))
|
|
|
|
|
{
|
|
|
|
|
if (gtk_builder_value_from_string_type (data->builder, G_TYPE_INT, elt2->data, &value, NULL))
|
|
|
|
|
y = g_value_get_int (&value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
child->children = g_list_remove (child->children, packing);
|
|
|
|
|
free_element (packing);
|
|
|
|
|
|
|
|
|
|
layout = add_element (object, "layout");
|
|
|
|
|
new_prop = add_element (layout, "property");
|
|
|
|
|
set_attribute_value (new_prop, "name", "transform");
|
|
|
|
|
|
|
|
|
|
transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (x, y));
|
|
|
|
|
new_prop->data = gsk_transform_to_string (transform);
|
|
|
|
|
gsk_transform_unref (transform);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
/* returns TRUE to remove the element from the parent */
|
2019-02-07 12:12:15 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
simplify_element (Element *element,
|
|
|
|
|
MyParserData *data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
GList *l;
|
2021-09-29 01:58:29 +00:00
|
|
|
|
GType type;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
if (!is_pcdata_element (element))
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2021-09-29 01:58:29 +00:00
|
|
|
|
g_clear_pointer (&element->data, g_free);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
2021-09-29 01:58:29 +00:00
|
|
|
|
else if (g_str_equal (element->element_name, "property"))
|
|
|
|
|
{
|
|
|
|
|
if (property_is_boolean (element, data))
|
|
|
|
|
{
|
|
|
|
|
const char *b = canonical_boolean_value (data, element->data);
|
|
|
|
|
g_free (element->data);
|
|
|
|
|
element->data = g_strdup (b);
|
|
|
|
|
}
|
|
|
|
|
else if (property_is_enum (element, data, &type))
|
|
|
|
|
{
|
|
|
|
|
char *e = canonical_enum_value (data, type, element->data);
|
|
|
|
|
g_free (element->data);
|
|
|
|
|
element->data = e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; element->attribute_names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (g_str_equal (element->attribute_names[i], "translatable"))
|
|
|
|
|
{
|
|
|
|
|
const char *b = canonical_boolean_value (data, element->attribute_values[i]);
|
|
|
|
|
g_free (element->attribute_values[i]);
|
|
|
|
|
element->attribute_values[i] = g_strdup (b);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
l = element->children;
|
|
|
|
|
while (l)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
GList *next = l->next;
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
if (simplify_element (child, data))
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
element->children = g_list_remove (element->children, child);
|
|
|
|
|
free_element (child);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
2019-02-07 12:12:15 +00:00
|
|
|
|
l = next;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
if (is_container_element (element) && element->children == NULL)
|
|
|
|
|
return TRUE;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
if (g_str_equal (element->element_name, "property") &&
|
|
|
|
|
property_can_be_omitted (element, data))
|
|
|
|
|
return TRUE;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2019-12-18 21:58:10 +00:00
|
|
|
|
if (g_str_equal (element->element_name, "binding"))
|
|
|
|
|
{
|
|
|
|
|
const char *property_name = get_attribute_value (element, "name");
|
|
|
|
|
const char *class_name = get_class_name (element);
|
|
|
|
|
if (!get_property_pspec (data, class_name, property_name, PROP_KIND_OBJECT))
|
|
|
|
|
warn_missing_property (element, data, class_name, property_name, PROP_KIND_OBJECT);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
simplify_tree (MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
simplify_element (data->root, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
rewrite_element (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
|
|
l = element->children;
|
|
|
|
|
while (l)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-05-05 17:09:17 +00:00
|
|
|
|
GList *next = l->next;
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
if (rewrite_element (child, data))
|
|
|
|
|
{
|
|
|
|
|
element->children = g_list_remove (element->children, child);
|
|
|
|
|
free_element (child);
|
|
|
|
|
}
|
|
|
|
|
l = next;
|
|
|
|
|
}
|
2019-02-07 20:34:54 +00:00
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
g_str_equal (get_class_name (element), "GtkStack"))
|
|
|
|
|
rewrite_stack (element, data);
|
2019-05-04 15:59:08 +00:00
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
g_str_equal (get_class_name (element), "GtkAssistant"))
|
|
|
|
|
rewrite_assistant (element, data);
|
2019-05-04 15:59:08 +00:00
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
g_str_equal (get_class_name (element), "GtkNotebook"))
|
|
|
|
|
rewrite_notebook (element, data);
|
2019-03-27 17:14:39 +00:00
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
(g_str_equal (get_class_name (element), "GtkActionBar") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkHeaderBar")))
|
|
|
|
|
rewrite_pack_type (element, data);
|
2019-03-28 00:03:34 +00:00
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
g_str_equal (get_class_name (element), "GtkToolbar"))
|
2020-11-01 19:13:49 +00:00
|
|
|
|
rewrite_toolbar (element, data);
|
2019-03-28 01:23:56 +00:00
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
g_str_equal (get_class_name (element), "GtkPaned"))
|
|
|
|
|
rewrite_paned (element, data);
|
2019-05-30 07:44:44 +00:00
|
|
|
|
|
|
|
|
|
if (element_is_object_or_template (element) &&
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkDialog"))
|
|
|
|
|
rewrite_dialog (element, data);
|
2019-03-28 16:21:52 +00:00
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
g_str_equal (get_class_name (element), "GtkOverlay"))
|
2020-11-01 16:14:03 +00:00
|
|
|
|
rewrite_overlay (element, data);
|
2019-04-04 22:33:11 +00:00
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
g_str_equal (get_class_name (element), "GtkGrid"))
|
|
|
|
|
rewrite_grid_layout (element, data);
|
2019-04-04 22:33:11 +00:00
|
|
|
|
|
2020-08-17 01:32:21 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
|
|
|
|
(g_str_equal (get_class_name (element), "GtkHBox") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkVBox") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkBox")))
|
|
|
|
|
rewrite_box (element, data);
|
|
|
|
|
|
2019-05-30 07:20:52 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
2019-05-05 17:09:17 +00:00
|
|
|
|
g_str_equal (get_class_name (element), "GtkFixed"))
|
2020-11-01 21:51:14 +00:00
|
|
|
|
rewrite_fixed (element, data);
|
2019-05-05 17:09:17 +00:00
|
|
|
|
|
2020-05-01 22:02:46 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
|
|
|
|
(g_str_equal (get_class_name (element), "GtkAspectFrame") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkComboBox") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkComboBoxText") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkFlowBoxChild") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkFrame") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkListBoxRow") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkOverlay") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkPopover") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkPopoverMenu") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkRevealer") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkScrolledWindow") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkSearchBar") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkViewport") ||
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkWindow")))
|
|
|
|
|
rewrite_bin_child (element, data);
|
|
|
|
|
|
2020-08-31 01:07:20 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkRadioButton"))
|
|
|
|
|
rewrite_radio_button (element, data);
|
|
|
|
|
|
2020-10-04 00:08:29 +00:00
|
|
|
|
if (element_is_object_or_template (element) &&
|
|
|
|
|
g_str_equal (get_class_name (element), "GtkScale"))
|
|
|
|
|
rewrite_scale (element, data);
|
|
|
|
|
|
2019-05-19 23:53:15 +00:00
|
|
|
|
if (g_str_equal (element->element_name, "property"))
|
|
|
|
|
maybe_rename_property (element, data);
|
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
if (g_str_equal (element->element_name, "property") &&
|
|
|
|
|
property_has_been_removed (element, data))
|
|
|
|
|
return TRUE;
|
2019-02-07 12:12:15 +00:00
|
|
|
|
|
2020-11-07 10:24:19 +00:00
|
|
|
|
if (g_str_equal (element->element_name, "requires"))
|
|
|
|
|
rewrite_requires (element, data);
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
return FALSE;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2019-05-05 17:09:17 +00:00
|
|
|
|
rewrite_tree (MyParserData *data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-05-05 17:09:17 +00:00
|
|
|
|
rewrite_element (data->root, data);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-04 15:59:08 +00:00
|
|
|
|
/* For properties which have changed their default
|
|
|
|
|
* value between 3 and 4, we make sure that their
|
|
|
|
|
* old default value is present in the tree before
|
|
|
|
|
* simplifying it.
|
|
|
|
|
*
|
|
|
|
|
* So far, this is just GtkWidget::visible,
|
|
|
|
|
* changing its default from 0 to 1.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
add_old_default_properties (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
const char *class_name;
|
|
|
|
|
GType type;
|
|
|
|
|
|
|
|
|
|
if (!g_str_equal (element->element_name, "object"))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
class_name = get_class_name (element);
|
|
|
|
|
type = g_type_from_name (class_name);
|
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_WIDGET))
|
|
|
|
|
{
|
|
|
|
|
GList *l;
|
|
|
|
|
gboolean has_visible = FALSE;
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *prop = l->data;
|
|
|
|
|
const char *name = get_attribute_value (prop, "name");
|
|
|
|
|
|
|
|
|
|
if (g_str_equal (prop->element_name, "property") &&
|
|
|
|
|
g_str_equal (name, "visible"))
|
|
|
|
|
has_visible = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!has_visible)
|
|
|
|
|
{
|
2020-11-01 19:13:49 +00:00
|
|
|
|
Element *new_prop;
|
|
|
|
|
|
|
|
|
|
new_prop = add_element (element, "property");
|
|
|
|
|
set_attribute_value (new_prop, "name", "visible");
|
2019-05-04 15:59:08 +00:00
|
|
|
|
new_prop->data = g_strdup ("0");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
enhance_element (Element *element,
|
|
|
|
|
MyParserData *data)
|
|
|
|
|
{
|
|
|
|
|
GList *l;
|
|
|
|
|
|
2020-11-11 00:19:40 +00:00
|
|
|
|
if (strcmp (element->element_name, "requires") == 0 &&
|
|
|
|
|
has_attribute (element, "lib", "gtk+"))
|
|
|
|
|
{
|
|
|
|
|
data->has_gtk_requires = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-04 15:59:08 +00:00
|
|
|
|
add_old_default_properties (element, data);
|
|
|
|
|
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
|
|
|
|
{
|
|
|
|
|
Element *child = l->data;
|
|
|
|
|
enhance_element (child, data);
|
|
|
|
|
}
|
2020-11-11 00:19:40 +00:00
|
|
|
|
|
|
|
|
|
if (element == data->root && !data->has_gtk_requires)
|
|
|
|
|
{
|
|
|
|
|
Element *requires = add_element (element, "requires");
|
|
|
|
|
set_attribute_value (requires, "lib", "gtk+");
|
|
|
|
|
set_attribute_value (requires, "version", "3.0");
|
|
|
|
|
}
|
2019-05-04 15:59:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
enhance_tree (MyParserData *data)
|
|
|
|
|
{
|
2019-05-05 17:09:17 +00:00
|
|
|
|
enhance_element (data->root, data);
|
2019-05-04 15:59:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
static void
|
|
|
|
|
dump_element (Element *element,
|
|
|
|
|
FILE *output,
|
|
|
|
|
int indent)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
g_fprintf (output, "%*s<%s", indent, "", element->element_name);
|
|
|
|
|
if (element->attribute_names[0])
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; element->attribute_names[i]; i++)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
char *escaped = g_markup_escape_text (element->attribute_values[i], -1);
|
|
|
|
|
g_fprintf (output, " %s=\"%s\"", element->attribute_names[i], escaped);
|
|
|
|
|
g_free (escaped);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-07 12:12:15 +00:00
|
|
|
|
if (element->children || element->data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
g_fprintf (output, ">");
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
if (element->children)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
|
|
g_fprintf (output, "\n");
|
|
|
|
|
for (l = element->children; l; l = l->next)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-07 12:12:15 +00:00
|
|
|
|
Element *child = l->data;
|
|
|
|
|
dump_element (child, output, indent + 2);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
2019-02-07 12:12:15 +00:00
|
|
|
|
g_fprintf (output, "%*s", indent, "");
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2019-02-07 12:12:15 +00:00
|
|
|
|
{
|
2019-12-13 19:03:20 +00:00
|
|
|
|
if (is_cdata_property (element))
|
|
|
|
|
{
|
|
|
|
|
g_fprintf (output, "<![CDATA[");
|
|
|
|
|
g_fprintf (output, "%s", element->data);
|
|
|
|
|
g_fprintf (output, "]]>");
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-11-01 16:15:08 +00:00
|
|
|
|
{
|
2019-12-13 19:03:20 +00:00
|
|
|
|
char *escaped = g_markup_escape_text (element->data, -1);
|
|
|
|
|
g_fprintf (output, "%s", escaped);
|
|
|
|
|
g_free (escaped);
|
|
|
|
|
}
|
2019-02-07 12:12:15 +00:00
|
|
|
|
}
|
|
|
|
|
g_fprintf (output, "</%s>\n", element->element_name);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
2019-02-07 12:12:15 +00:00
|
|
|
|
else
|
2019-05-04 15:59:08 +00:00
|
|
|
|
g_fprintf (output, "/>\n");
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-28 23:28:05 +00:00
|
|
|
|
static void
|
|
|
|
|
write_xml_declaration (FILE *output)
|
|
|
|
|
{
|
|
|
|
|
g_fprintf (output, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 09:12:09 +00:00
|
|
|
|
static void
|
2019-02-07 12:12:15 +00:00
|
|
|
|
dump_tree (MyParserData *data)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-03-28 23:28:05 +00:00
|
|
|
|
write_xml_declaration (data->output);
|
2019-02-07 12:12:15 +00:00
|
|
|
|
dump_element (data->root, data->output, 0);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-18 10:04:15 +00:00
|
|
|
|
static gboolean
|
2019-02-07 17:24:49 +00:00
|
|
|
|
simplify_file (const char *filename,
|
|
|
|
|
gboolean replace,
|
|
|
|
|
gboolean convert3to4)
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
|
|
|
|
GMarkupParseContext *context;
|
2020-07-24 18:40:36 +00:00
|
|
|
|
char *buffer;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
MyParserData data;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
2019-02-07 17:24:49 +00:00
|
|
|
|
data.input_filename = filename;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
data.output_filename = NULL;
|
2019-02-07 17:24:49 +00:00
|
|
|
|
data.convert3to4 = convert3to4;
|
2020-11-11 00:19:40 +00:00
|
|
|
|
data.has_gtk_requires = FALSE;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
|
|
|
|
if (replace)
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
fd = g_file_open_tmp ("gtk-builder-tool-XXXXXX", &data.output_filename, NULL);
|
|
|
|
|
data.output = fdopen (fd, "w");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
data.output = stdout;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 17:24:49 +00:00
|
|
|
|
if (!g_file_get_contents (filename, &buffer, NULL, &error))
|
2019-02-07 09:12:09 +00:00
|
|
|
|
{
|
2019-02-08 18:24:53 +00:00
|
|
|
|
g_printerr (_("Can’t load “%s”: %s\n"), filename, error->message);
|
2019-02-07 17:24:49 +00:00
|
|
|
|
return FALSE;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
data.root = NULL;
|
|
|
|
|
data.current = NULL;
|
|
|
|
|
data.value = g_string_new ("");
|
2019-02-07 09:12:09 +00:00
|
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
{
|
2019-02-08 18:24:53 +00:00
|
|
|
|
g_printerr (_("Can’t parse “%s”: %s\n"), filename, error->message);
|
2021-12-13 18:52:50 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!g_markup_parse_context_end_parse (context, &error))
|
|
|
|
|
{
|
2022-01-24 17:04:17 +00:00
|
|
|
|
g_printerr (_("Can’t parse “%s”: %s\n"), filename, error->message);
|
2019-02-07 17:24:49 +00:00
|
|
|
|
return FALSE;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-13 19:44:40 +00:00
|
|
|
|
if (data.root == NULL)
|
|
|
|
|
{
|
2022-01-24 17:04:17 +00:00
|
|
|
|
g_printerr (_("Can’t parse “%s”\n"), filename);
|
2021-12-13 19:44:40 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 12:12:15 +00:00
|
|
|
|
data.builder = gtk_builder_new ();
|
|
|
|
|
|
2019-05-05 17:09:17 +00:00
|
|
|
|
if (data.convert3to4)
|
|
|
|
|
{
|
|
|
|
|
enhance_tree (&data);
|
|
|
|
|
rewrite_tree (&data);
|
|
|
|
|
}
|
2019-02-07 12:12:15 +00:00
|
|
|
|
simplify_tree (&data);
|
|
|
|
|
|
|
|
|
|
dump_tree (&data);
|
|
|
|
|
|
2019-02-07 09:12:09 +00:00
|
|
|
|
fclose (data.output);
|
|
|
|
|
|
|
|
|
|
if (data.output_filename)
|
|
|
|
|
{
|
|
|
|
|
char *content;
|
|
|
|
|
gsize length;
|
|
|
|
|
|
|
|
|
|
if (!g_file_get_contents (data.output_filename, &content, &length, &error))
|
|
|
|
|
{
|
2019-02-08 18:24:53 +00:00
|
|
|
|
g_printerr (_("Failed to read “%s”: %s\n"), data.output_filename, error->message);
|
2019-02-07 17:24:49 +00:00
|
|
|
|
return FALSE;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!g_file_set_contents (data.input_filename, content, length, &error))
|
|
|
|
|
{
|
2019-02-08 18:24:53 +00:00
|
|
|
|
g_printerr (_("Failed to write %s: “%s”\n"), data.input_filename, error->message);
|
2019-02-07 17:24:49 +00:00
|
|
|
|
return FALSE;
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-07 17:24:49 +00:00
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_simplify (int *argc,
|
|
|
|
|
const char ***argv)
|
|
|
|
|
{
|
|
|
|
|
gboolean replace = FALSE;
|
|
|
|
|
gboolean convert3to4 = FALSE;
|
|
|
|
|
char **filenames = NULL;
|
2022-04-17 15:59:06 +00:00
|
|
|
|
GOptionContext *context;
|
2019-02-07 17:24:49 +00:00
|
|
|
|
const GOptionEntry entries[] = {
|
2022-04-17 15:59:06 +00:00
|
|
|
|
{ "replace", 0, 0, G_OPTION_ARG_NONE, &replace, N_("Replace the file"), NULL },
|
|
|
|
|
{ "3to4", 0, 0, G_OPTION_ARG_NONE, &convert3to4, N_("Convert from GTK 3 to GTK 4"), NULL },
|
|
|
|
|
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE") },
|
2019-02-07 17:24:49 +00:00
|
|
|
|
{ NULL, }
|
|
|
|
|
};
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
int i;
|
|
|
|
|
|
2022-04-17 15:59:06 +00:00
|
|
|
|
g_set_prgname ("gtk4-builder-tool simplify");
|
|
|
|
|
context = g_option_context_new (NULL);
|
|
|
|
|
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
|
|
|
|
|
g_option_context_add_main_entries (context, entries, NULL);
|
|
|
|
|
g_option_context_set_summary (context, _("Simplify the file."));
|
2019-02-07 17:24:49 +00:00
|
|
|
|
|
2022-04-17 15:59:06 +00:00
|
|
|
|
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
|
2019-02-07 17:24:49 +00:00
|
|
|
|
{
|
|
|
|
|
g_printerr ("%s\n", error->message);
|
|
|
|
|
g_error_free (error);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-17 15:59:06 +00:00
|
|
|
|
g_option_context_free (context);
|
2019-02-07 17:24:49 +00:00
|
|
|
|
|
|
|
|
|
if (filenames == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_printerr (_("No .ui file specified\n"));
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_strv_length (filenames) > 1 && !replace)
|
|
|
|
|
{
|
|
|
|
|
g_printerr (_("Can only simplify a single .ui file without --replace\n"));
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; filenames[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!simplify_file (filenames[i], replace, convert3to4))
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
2022-04-17 15:59:06 +00:00
|
|
|
|
|
|
|
|
|
g_strfreev (filenames);
|
2019-02-07 09:12:09 +00:00
|
|
|
|
}
|