mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-13 22:10:08 +00:00
Merge branch 'builder-tool-scope' into 'main'
docs: Update gtk4-builder-tool docs See merge request GNOME/gtk!5145
This commit is contained in:
commit
8a3f1a1fa1
@ -13,7 +13,7 @@ SYNOPSIS
|
||||
| **gtk4-builder-tool** <COMMAND> [OPTIONS...] <FILE>
|
||||
|
|
||||
| **gtk4-builder-tool** validate [OPTIONS...] <FILE>
|
||||
| **gtk4-builder-tool** enumerate <FILE>
|
||||
| **gtk4-builder-tool** enumerate [OPTIONS...] <FILE>
|
||||
| **gtk4-builder-tool** simplify [OPTIONS...] <FILE>
|
||||
| **gtk4-builder-tool** preview [OPTIONS...] <FILE>
|
||||
| **gtk4-builder-tool** screenshot [OPTIONS...] <FILE>
|
||||
@ -40,9 +40,13 @@ errors to ``stderr``.
|
||||
Enumeration
|
||||
^^^^^^^^^^^
|
||||
|
||||
The ``enumerate`` command lists all the named objects that are present in the UI
|
||||
The ``enumerate`` command prints all the named objects that are present in the UI
|
||||
definition file.
|
||||
|
||||
``--callbacks``
|
||||
|
||||
Print the names of callbacks as well.
|
||||
|
||||
Preview
|
||||
^^^^^^^
|
||||
|
||||
|
213
tools/fake-scope.c
Normal file
213
tools/fake-scope.c
Normal file
@ -0,0 +1,213 @@
|
||||
/* 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fake-scope.h"
|
||||
#include "gtk-builder-tool.h"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
/* {{{ Scope implementation */
|
||||
|
||||
struct _FakeScope
|
||||
{
|
||||
GtkBuilderCScope parent;
|
||||
|
||||
GPtrArray *types;
|
||||
GPtrArray *callbacks;
|
||||
};
|
||||
|
||||
static GtkBuilderScopeInterface *parent_scope_iface;
|
||||
|
||||
static void
|
||||
dummy_cb (void)
|
||||
{
|
||||
}
|
||||
|
||||
static GClosure *
|
||||
fake_scope_create_closure (GtkBuilderScope *scope,
|
||||
GtkBuilder *builder,
|
||||
const char *function_name,
|
||||
GtkBuilderClosureFlags flags,
|
||||
GObject *object,
|
||||
GError **error)
|
||||
{
|
||||
FakeScope *self = FAKE_SCOPE (scope);
|
||||
GClosure *closure;
|
||||
gboolean swapped = flags & GTK_BUILDER_CLOSURE_SWAPPED;
|
||||
|
||||
g_ptr_array_add (self->callbacks, g_strdup (function_name));
|
||||
|
||||
if (object == NULL)
|
||||
object = gtk_builder_get_current_object (builder);
|
||||
|
||||
if (object)
|
||||
{
|
||||
if (swapped)
|
||||
closure = g_cclosure_new_object_swap (dummy_cb, object);
|
||||
else
|
||||
closure = g_cclosure_new_object (dummy_cb, object);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (swapped)
|
||||
closure = g_cclosure_new_swap (dummy_cb, NULL, NULL);
|
||||
else
|
||||
closure = g_cclosure_new (dummy_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
||||
static GType
|
||||
fake_scope_get_type_from_name (GtkBuilderScope *scope,
|
||||
GtkBuilder *builder,
|
||||
const char *type_name)
|
||||
{
|
||||
FakeScope *self = FAKE_SCOPE (scope);
|
||||
GType type;
|
||||
|
||||
type = parent_scope_iface->get_type_from_name (scope, builder, type_name);
|
||||
|
||||
g_ptr_array_add (self->types, g_strdup (type_name));
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static GType
|
||||
fake_scope_get_type_from_function (GtkBuilderScope *scope,
|
||||
GtkBuilder *builder,
|
||||
const char *function_name)
|
||||
{
|
||||
FakeScope *self = FAKE_SCOPE (scope);
|
||||
GType type;
|
||||
|
||||
type = parent_scope_iface->get_type_from_function (scope, builder, function_name);
|
||||
|
||||
if (type != G_TYPE_INVALID)
|
||||
g_ptr_array_add (self->types, g_strdup (g_type_name (type)));
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static void
|
||||
fake_scope_scope_init (GtkBuilderScopeInterface *iface)
|
||||
{
|
||||
parent_scope_iface = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->get_type_from_name = fake_scope_get_type_from_name;
|
||||
iface->get_type_from_function = fake_scope_get_type_from_function;
|
||||
iface->create_closure = fake_scope_create_closure;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (FakeScope, fake_scope, GTK_TYPE_BUILDER_CSCOPE,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDER_SCOPE,
|
||||
fake_scope_scope_init))
|
||||
|
||||
static void
|
||||
fake_scope_init (FakeScope *scope)
|
||||
{
|
||||
scope->types = g_ptr_array_new_with_free_func (g_free);
|
||||
scope->callbacks = g_ptr_array_new_with_free_func (g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
fake_scope_finalize (GObject *object)
|
||||
{
|
||||
FakeScope *self = FAKE_SCOPE (object);
|
||||
|
||||
g_ptr_array_unref (self->types);
|
||||
g_ptr_array_unref (self->callbacks);
|
||||
|
||||
G_OBJECT_CLASS (fake_scope_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fake_scope_class_init (FakeScopeClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS (class)->finalize = fake_scope_finalize;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ API */
|
||||
|
||||
FakeScope *
|
||||
fake_scope_new (void)
|
||||
{
|
||||
return g_object_new (fake_scope_get_type (), NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_strings (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const char **aa = (const char **)a;
|
||||
const char **bb = (const char **)b;
|
||||
|
||||
return strcmp (*aa, *bb);
|
||||
}
|
||||
|
||||
static void
|
||||
g_ptr_array_unique (GPtrArray *array,
|
||||
GCompareFunc cmp)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 1;
|
||||
while (i < array->len)
|
||||
{
|
||||
gconstpointer *one = g_ptr_array_index (array, i - 1);
|
||||
gconstpointer *two = g_ptr_array_index (array, i);
|
||||
|
||||
if (cmp (&one, &two) == 0)
|
||||
g_ptr_array_remove_index (array, i);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
fake_scope_get_types (FakeScope *self)
|
||||
{
|
||||
g_ptr_array_sort (self->types, cmp_strings);
|
||||
g_ptr_array_unique (self->types, cmp_strings);
|
||||
|
||||
return self->types;
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
fake_scope_get_callbacks (FakeScope *self)
|
||||
{
|
||||
g_ptr_array_sort (self->callbacks, cmp_strings);
|
||||
g_ptr_array_unique (self->callbacks, cmp_strings);
|
||||
|
||||
return self->callbacks;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* vim:set foldmethod=marker expandtab: */
|
9
tools/fake-scope.h
Normal file
9
tools/fake-scope.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FakeScope, fake_scope, FAKE, SCOPE, GtkBuilderCScope)
|
||||
|
||||
FakeScope * fake_scope_new (void);
|
||||
GPtrArray * fake_scope_get_types (FakeScope *self);
|
||||
GPtrArray * fake_scope_get_callbacks (FakeScope *self);
|
@ -29,6 +29,7 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtkbuilderprivate.h"
|
||||
#include "gtk-builder-tool.h"
|
||||
#include "fake-scope.h"
|
||||
|
||||
static const char *
|
||||
object_get_id (GObject *object)
|
||||
@ -42,15 +43,16 @@ object_get_id (GObject *object)
|
||||
void
|
||||
do_enumerate (int *argc, const char ***argv)
|
||||
{
|
||||
FakeScope *scope;
|
||||
GtkBuilder *builder;
|
||||
GError *error = NULL;
|
||||
int ret;
|
||||
GSList *list, *l;
|
||||
GObject *object;
|
||||
const char *name;
|
||||
gboolean callbacks = FALSE;
|
||||
char **filenames = NULL;
|
||||
GOptionContext *context;
|
||||
const GOptionEntry entries[] = {
|
||||
{ "callbacks", 0, 0, G_OPTION_ARG_NONE, &callbacks, "Also print callbacks", NULL },
|
||||
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE") },
|
||||
{ NULL, }
|
||||
};
|
||||
@ -59,7 +61,7 @@ do_enumerate (int *argc, const char ***argv)
|
||||
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, _("List all named objects."));
|
||||
g_option_context_set_summary (context, _("Print all named objects."));
|
||||
|
||||
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
|
||||
{
|
||||
@ -83,6 +85,9 @@ do_enumerate (int *argc, const char ***argv)
|
||||
}
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
scope = fake_scope_new ();
|
||||
gtk_builder_set_scope (builder, GTK_BUILDER_SCOPE (scope));
|
||||
|
||||
ret = gtk_builder_add_from_file (builder, filenames[0], &error);
|
||||
|
||||
if (ret == 0)
|
||||
@ -91,11 +96,14 @@ do_enumerate (int *argc, const char ***argv)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (callbacks)
|
||||
g_print ("Objects:\n");
|
||||
|
||||
list = gtk_builder_get_objects (builder);
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
object = l->data;
|
||||
name = object_get_id (object);
|
||||
GObject *object = l->data;
|
||||
const char *name = object_get_id (object);
|
||||
if (g_str_has_prefix (name, "___") && g_str_has_suffix (name, "___"))
|
||||
continue;
|
||||
|
||||
@ -103,6 +111,27 @@ do_enumerate (int *argc, const char ***argv)
|
||||
}
|
||||
g_slist_free (list);
|
||||
|
||||
if (callbacks)
|
||||
{
|
||||
GPtrArray *names;
|
||||
gboolean need_prefix = TRUE;
|
||||
|
||||
names = fake_scope_get_callbacks (scope);
|
||||
for (int i = 0; i < names->len; i++)
|
||||
{
|
||||
const char *name = g_ptr_array_index (names, i);
|
||||
|
||||
if (need_prefix)
|
||||
{
|
||||
need_prefix = FALSE;
|
||||
g_print ("\nCallbacks:\n");
|
||||
}
|
||||
|
||||
g_print ("%s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (scope);
|
||||
g_object_unref (builder);
|
||||
|
||||
g_strfreev (filenames);
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtkbuilderprivate.h"
|
||||
#include "gtk-builder-tool.h"
|
||||
#include "fake-scope.h"
|
||||
|
||||
|
||||
static GType
|
||||
make_fake_type (const char *type_name,
|
||||
@ -54,73 +56,10 @@ make_fake_type (const char *type_name,
|
||||
0);
|
||||
}
|
||||
|
||||
static void
|
||||
do_validate_template (const char *filename,
|
||||
const char *type_name,
|
||||
const char *parent_name)
|
||||
{
|
||||
GType template_type;
|
||||
GObject *object;
|
||||
GtkBuilder *builder;
|
||||
GError *error = NULL;
|
||||
int ret;
|
||||
|
||||
/* Only make a fake type if it doesn't exist yet.
|
||||
* This lets us e.g. validate the GtkFileChooserWidget template.
|
||||
*/
|
||||
template_type = g_type_from_name (type_name);
|
||||
if (template_type == G_TYPE_INVALID)
|
||||
template_type = make_fake_type (type_name, parent_name);
|
||||
|
||||
object = g_object_new (template_type, NULL);
|
||||
if (!object)
|
||||
{
|
||||
g_printerr ("Failed to create an instance of the template type %s\n", type_name);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
ret = gtk_builder_extend_with_template (builder, object , template_type, " ", 1, &error);
|
||||
if (ret)
|
||||
ret = gtk_builder_add_from_file (builder, filename, &error);
|
||||
g_object_unref (builder);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
/* {{{ Deprecations */
|
||||
|
||||
static gboolean
|
||||
parse_template_error (const char *message,
|
||||
char **class_name,
|
||||
char **parent_name)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = strstr (message, "(class '");
|
||||
if (p)
|
||||
{
|
||||
*class_name = g_strdup (p + strlen ("(class '"));
|
||||
p = strstr (*class_name, "'");
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
p = strstr (message, ", parent '");
|
||||
if (p)
|
||||
{
|
||||
*parent_name = g_strdup (p + strlen (", parent '"));
|
||||
p = strstr (*parent_name, "'");
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return *class_name && *parent_name;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_deprecated (GObject *object)
|
||||
is_deprecated (const char *name)
|
||||
{
|
||||
const char *names[] = {
|
||||
"GtkAppChooser",
|
||||
@ -160,52 +99,33 @@ is_deprecated (GObject *object)
|
||||
NULL
|
||||
};
|
||||
|
||||
return g_strv_contains (names, G_OBJECT_TYPE_NAME (object));
|
||||
}
|
||||
|
||||
static const char *
|
||||
object_get_id (GObject *object)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
if (GTK_IS_BUILDABLE (object))
|
||||
name = gtk_buildable_get_buildable_id (GTK_BUILDABLE (object));
|
||||
else
|
||||
name = g_object_get_data (object, "gtk-builder-id");
|
||||
|
||||
if (g_str_has_prefix (name, "___"))
|
||||
return NULL;
|
||||
|
||||
return name;
|
||||
return g_strv_contains (names, name);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_deprecations (GtkBuilder *builder,
|
||||
GError **error)
|
||||
fake_scope_check_deprecations (FakeScope *self,
|
||||
GError **error)
|
||||
{
|
||||
GSList *objects;
|
||||
GPtrArray *types;
|
||||
GString *s;
|
||||
|
||||
types = fake_scope_get_types (self);
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
objects = gtk_builder_get_objects (builder);
|
||||
for (GSList *l = objects; l; l = l->next)
|
||||
for (int i = 0; i < types->len; i++)
|
||||
{
|
||||
GObject *obj = l->data;
|
||||
const char *name = g_ptr_array_index (types, i);
|
||||
|
||||
if (is_deprecated (obj))
|
||||
if (is_deprecated (name))
|
||||
{
|
||||
if (s->len == 0)
|
||||
g_string_append (s, "Deprecated types:\n");
|
||||
g_string_append_printf (s, "%s", G_OBJECT_TYPE_NAME (obj));
|
||||
if (object_get_id (obj))
|
||||
g_string_append_printf (s, " (named '%s')", object_get_id (obj));
|
||||
g_string_append_printf (s, "%s", name);
|
||||
g_string_append (s, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_free (objects);
|
||||
|
||||
if (s->len > 0)
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, s->str);
|
||||
|
||||
@ -214,37 +134,118 @@ check_deprecations (GtkBuilder *builder,
|
||||
return *error == NULL;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
static gboolean
|
||||
validate_template (const char *filename,
|
||||
const char *type_name,
|
||||
const char *parent_name,
|
||||
gboolean deprecations)
|
||||
{
|
||||
GType template_type;
|
||||
GObject *object;
|
||||
FakeScope *scope;
|
||||
GtkBuilder *builder;
|
||||
GError *error = NULL;
|
||||
gboolean ret;
|
||||
|
||||
/* Only make a fake type if it doesn't exist yet.
|
||||
* This lets us e.g. validate the GtkFileChooserWidget template.
|
||||
*/
|
||||
template_type = g_type_from_name (type_name);
|
||||
if (template_type == G_TYPE_INVALID)
|
||||
template_type = make_fake_type (type_name, parent_name);
|
||||
|
||||
object = g_object_new (template_type, NULL);
|
||||
if (!object)
|
||||
{
|
||||
g_printerr ("Failed to create an instance of the template type %s\n", type_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
scope = fake_scope_new ();
|
||||
gtk_builder_set_scope (builder, GTK_BUILDER_SCOPE (scope));
|
||||
ret = gtk_builder_extend_with_template (builder, object, template_type, " ", 1, &error);
|
||||
if (ret)
|
||||
ret = gtk_builder_add_from_file (builder, filename, &error);
|
||||
if (ret && deprecations)
|
||||
ret = fake_scope_check_deprecations (scope, &error);
|
||||
g_object_unref (scope);
|
||||
g_object_unref (builder);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_template_error (const char *message,
|
||||
char **class_name,
|
||||
char **parent_name)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = strstr (message, "(class '");
|
||||
if (p)
|
||||
{
|
||||
*class_name = g_strdup (p + strlen ("(class '"));
|
||||
p = strstr (*class_name, "'");
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
p = strstr (message, ", parent '");
|
||||
if (p)
|
||||
{
|
||||
*parent_name = g_strdup (p + strlen (", parent '"));
|
||||
p = strstr (*parent_name, "'");
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return *class_name && *parent_name;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
validate_file (const char *filename,
|
||||
gboolean deprecations)
|
||||
{
|
||||
FakeScope *scope;
|
||||
GtkBuilder *builder;
|
||||
GError *error = NULL;
|
||||
int ret;
|
||||
gboolean ret;
|
||||
char *class_name = NULL;
|
||||
char *parent_name = NULL;
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
scope = fake_scope_new ();
|
||||
gtk_builder_set_scope (builder, GTK_BUILDER_SCOPE (scope));
|
||||
ret = gtk_builder_add_from_file (builder, filename, &error);
|
||||
if (ret && deprecations)
|
||||
ret = check_deprecations (builder, &error);
|
||||
ret = fake_scope_check_deprecations (scope, &error);
|
||||
g_object_unref (scope);
|
||||
g_object_unref (builder);
|
||||
|
||||
if (ret == 0)
|
||||
if (!ret)
|
||||
{
|
||||
if (g_error_matches (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_UNHANDLED_TAG) &&
|
||||
parse_template_error (error->message, &class_name, &parent_name))
|
||||
{
|
||||
do_validate_template (filename, class_name, parent_name);
|
||||
ret = validate_template (filename, class_name, parent_name, deprecations);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
@ -284,3 +285,5 @@ do_validate (int *argc, const char ***argv)
|
||||
|
||||
g_strfreev (filenames);
|
||||
}
|
||||
|
||||
/* vim:set foldmethod=marker expandtab: */
|
||||
|
@ -29,7 +29,8 @@ gtk_tools = [
|
||||
'gtk-builder-tool-validate.c',
|
||||
'gtk-builder-tool-enumerate.c',
|
||||
'gtk-builder-tool-screenshot.c',
|
||||
'gtk-builder-tool-preview.c'], [libgtk_dep] ],
|
||||
'gtk-builder-tool-preview.c',
|
||||
'fake-scope.c'], [libgtk_dep] ],
|
||||
['gtk4-update-icon-cache', ['updateiconcache.c'] + extra_update_icon_cache_objs, [ libgtk_static_dep ] ],
|
||||
['gtk4-encode-symbolic-svg', ['encodesymbolic.c'], [ libgtk_static_dep ] ],
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user