diff options
author | Matthias Clasen <mclasen@redhat.com> | 2022-10-19 18:34:25 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2022-10-19 18:34:25 +0000 |
commit | 8a3f1a1fa1ba23e2d75400146360f5eaa45b97c7 (patch) | |
tree | b4ff1c46037dd484123567d757025dd38ac85bc3 | |
parent | aaf5c43e7854eb8a39f90925da98150fe99fa5da (diff) | |
parent | 46c7c0c4e69b81634f16fdd82bc62e8012d24168 (diff) | |
download | gtk+-8a3f1a1fa1ba23e2d75400146360f5eaa45b97c7.tar.gz |
Merge branch 'builder-tool-scope' into 'main'
docs: Update gtk4-builder-tool docs
See merge request GNOME/gtk!5145
-rw-r--r-- | docs/reference/gtk/gtk4-builder-tool.rst | 8 | ||||
-rw-r--r-- | tools/fake-scope.c | 213 | ||||
-rw-r--r-- | tools/fake-scope.h | 9 | ||||
-rw-r--r-- | tools/gtk-builder-tool-enumerate.c | 39 | ||||
-rw-r--r-- | tools/gtk-builder-tool-validate.c | 203 | ||||
-rw-r--r-- | tools/meson.build | 3 |
6 files changed, 367 insertions, 108 deletions
diff --git a/docs/reference/gtk/gtk4-builder-tool.rst b/docs/reference/gtk/gtk4-builder-tool.rst index b3d08863b2..a7e38e73d4 100644 --- a/docs/reference/gtk/gtk4-builder-tool.rst +++ b/docs/reference/gtk/gtk4-builder-tool.rst @@ -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 ^^^^^^^ diff --git a/tools/fake-scope.c b/tools/fake-scope.c new file mode 100644 index 0000000000..8234d577a8 --- /dev/null +++ b/tools/fake-scope.c @@ -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: */ diff --git a/tools/fake-scope.h b/tools/fake-scope.h new file mode 100644 index 0000000000..05234129b8 --- /dev/null +++ b/tools/fake-scope.h @@ -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); diff --git a/tools/gtk-builder-tool-enumerate.c b/tools/gtk-builder-tool-enumerate.c index f0c6c8dc7e..81c4cfc555 100644 --- a/tools/gtk-builder-tool-enumerate.c +++ b/tools/gtk-builder-tool-enumerate.c @@ -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); diff --git a/tools/gtk-builder-tool-validate.c b/tools/gtk-builder-tool-validate.c index f887412700..244771f875 100644 --- a/tools/gtk-builder-tool-validate.c +++ b/tools/gtk-builder-tool-validate.c @@ -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: */ diff --git a/tools/meson.build b/tools/meson.build index 52afd5433d..0e90d88945 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -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 ] ], ] |