[gtkmm] Add Gtk::BuilderScope and BuilderCScope
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtkmm] Add Gtk::BuilderScope and BuilderCScope
- Date: Mon, 6 Jul 2020 13:13:09 +0000 (UTC)
commit 33e9759790c264c3ab2a8445463caf45cd605dda
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date: Mon Jul 6 15:10:21 2020 +0200
Add Gtk::BuilderScope and BuilderCScope
Override the get_type_from_name() vfunc in BuilderScope, just like
the get_type_from_name() vfunc in Builder is overridden in gtkmm3.
Set a GtkBuilderScope with an overridden vfunc in Builder's default
constructor. Builder::get_widget_derived() can then (like in gtkmm3)
instantiate gtkmm-derived types without gtkmm__ prefixes in the .ui file.
Fixes #61
.gitignore | 4 +++
gtk/gtkmm/meson.build | 2 ++
gtk/src/buildable.ccg | 70 +++++++++++++++++++++++++++++++++++++++++++++++
gtk/src/buildable.hg | 27 ++++++++++++++++++
gtk/src/builder.ccg | 19 +++++++++++++
gtk/src/builder.hg | 29 ++++++++++----------
gtk/src/buildercscope.ccg | 17 ++++++++++++
gtk/src/buildercscope.hg | 50 +++++++++++++++++++++++++++++++++
gtk/src/builderscope.ccg | 66 ++++++++++++++++++++++++++++++++++++++++++++
gtk/src/builderscope.hg | 65 +++++++++++++++++++++++++++++++++++++++++++
gtk/src/filelist.am | 2 ++
tests/builder/main.cc | 9 ++++++
12 files changed, 345 insertions(+), 15 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 4872f109..a4dbb8d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -179,6 +179,10 @@ gtk/gtkmm/buildable.cc
gtk/gtkmm/buildable.h
gtk/gtkmm/builder.cc
gtk/gtkmm/builder.h
+gtk/gtkmm/buildercscope.cc
+gtk/gtkmm/buildercscope.h
+gtk/gtkmm/builderscope.cc
+gtk/gtkmm/builderscope.h
gtk/gtkmm/button.cc
gtk/gtkmm/button.h
gtk/gtkmm/calendar.cc
diff --git a/gtk/gtkmm/meson.build b/gtk/gtkmm/meson.build
index 887ccb3f..0fe6011b 100644
--- a/gtk/gtkmm/meson.build
+++ b/gtk/gtkmm/meson.build
@@ -47,6 +47,8 @@ gtkmm_any_hg_ccg_basenames = [
'boxlayout',
'buildable',
'builder',
+ 'buildercscope',
+ 'builderscope',
'button',
'calendar',
'cellarea',
diff --git a/gtk/src/buildable.ccg b/gtk/src/buildable.ccg
index f10e0efc..d1756cc0 100644
--- a/gtk/src/buildable.ccg
+++ b/gtk/src/buildable.ccg
@@ -16,4 +16,74 @@
*/
#include <gtk/gtk.h>
+#include <gtkmm/builder.h>
+#include <cstring>
+namespace Gtk
+{
+
+//static
+gboolean Buildable_Class::custom_tag_start_vfunc_callback(
+ GtkBuildable* buildable,
+ GtkBuilder* builder,
+ GObject* child,
+ const gchar* tagname,
+ GtkBuildableParser* parser,
+ gpointer* data)
+{
+ // If it's a TreeModel (such as ListStore or TreeStore) and it's the start
+ // of a <columns> element, inform the Builder that the get_type_from_name()
+ // vfunc in BuilderScope shall not search for gtkmm-derived types.
+ // See https://bugzilla.gnome.org/show_bug.cgi?id=742637
+ if (GTK_IS_TREE_MODEL(buildable) && std::strcmp(tagname, "columns") == 0)
+ {
+ const auto cpp_builder = dynamic_cast<Builder*>(
+ Glib::ObjectBase::_get_current_wrapper((GObject*)builder));
+ if (cpp_builder)
+ cpp_builder->set_no_gtkmm_derived_types(true);
+ }
+
+ const auto base = static_cast<BaseClassType*>(
+ g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C
interface).
+ g_type_interface_peek(G_OBJECT_GET_CLASS(buildable), CppObjectType::get_type()) // Get the interface.
+ )
+ );
+
+ // Call the original underlying C function:
+ if (base && base->custom_tag_start)
+ return (*base->custom_tag_start)(buildable, builder, child, tagname, parser, data);
+ return false;
+}
+
+//static
+void Buildable_Class::custom_tag_end_vfunc_callback(
+ GtkBuildable* buildable,
+ GtkBuilder* builder,
+ GObject* child,
+ const gchar* tagname,
+ gpointer data)
+{
+ const auto base = static_cast<BaseClassType*>(
+ g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C
interface).
+ g_type_interface_peek(G_OBJECT_GET_CLASS(buildable), CppObjectType::get_type()) // Get the interface.
+ )
+ );
+
+ // Call the original underlying C function:
+ if (base && base->custom_tag_end)
+ (*base->custom_tag_end)(buildable, builder, child, tagname, data);
+
+ // If it's a TreeModel (such as ListStore or TreeStore) and it's the end
+ // of a </columns> element, inform the Builder that the get_type_from_name()
+ // vfunc in BuilderScope shall resume search for gtkmm-derived types.
+ // See https://bugzilla.gnome.org/show_bug.cgi?id=742637
+ if (GTK_IS_TREE_MODEL(buildable) && std::strcmp(tagname, "columns") == 0)
+ {
+ const auto cpp_builder = dynamic_cast<Builder*>(
+ Glib::ObjectBase::_get_current_wrapper((GObject*)builder));
+ if (cpp_builder)
+ cpp_builder->set_no_gtkmm_derived_types(false);
+ }
+}
+
+} // namespace Gtk
diff --git a/gtk/src/buildable.hg b/gtk/src/buildable.hg
index 52ab31df..ce3aceea 100644
--- a/gtk/src/buildable.hg
+++ b/gtk/src/buildable.hg
@@ -85,6 +85,33 @@ public:
*/
//TODO: Properties, signals, vfuncs.
+
+#m4begin
+dnl //Custom-coded vfuncs:
+dnl
+ _PUSH(SECTION_CC_PRE_INCLUDES)
+ // Needed before gtkmm/private/buildable_p.h is included.
+ typedef struct _GtkBuilder GtkBuilder;
+ typedef struct _GtkBuildableParser GtkBuildableParser;
+ _SECTION(SECTION_PCC_CLASS_INIT_VFUNCS)
+ klass->custom_tag_start = &custom_tag_start_vfunc_callback;
+ klass->custom_tag_end = &custom_tag_end_vfunc_callback;
+ _SECTION(SECTION_PH_VFUNCS)
+ static gboolean custom_tag_start_vfunc_callback(
+ GtkBuildable* buildable,
+ GtkBuilder* builder,
+ GObject* child,
+ const gchar* tagname,
+ GtkBuildableParser* parser,
+ gpointer* data);
+ static void custom_tag_end_vfunc_callback(
+ GtkBuildable* buildable,
+ GtkBuilder* builder,
+ GObject* child,
+ const gchar* tagname,
+ gpointer data);
+ _POP()
+#m4end
};
} // namespace Gtk
diff --git a/gtk/src/builder.ccg b/gtk/src/builder.ccg
index 847bcecc..81b4ed34 100644
--- a/gtk/src/builder.ccg
+++ b/gtk/src/builder.ccg
@@ -17,11 +17,30 @@
#include <glibmm/vectorutils.h>
#include <gtkmm/application.h>
+#include <gtkmm/buildercscope.h>
#include <gtk/gtk.h>
namespace Gtk
{
+// Called from Buildable
+void Builder::set_no_gtkmm_derived_types(bool status)
+{
+ no_gtkmm_derived_types = status;
+}
+
+// Called from BuilderScope
+bool Builder::get_no_gtkmm_derived_types() const
+{
+ return no_gtkmm_derived_types;
+}
+
+Builder::Builder()
+: // Set a scope that can find gtkmm-derived GTypes.
+ _CONSTRUCT("scope", BuilderCScope::create()->gobj())
+{
+}
+
// static
Glib::RefPtr<Builder> Builder::create_from_file(const std::string& filename)
{
diff --git a/gtk/src/builder.hg b/gtk/src/builder.hg
index 58ab8423..4ce3fff0 100644
--- a/gtk/src/builder.hg
+++ b/gtk/src/builder.hg
@@ -78,8 +78,8 @@ class GTKMM_API Builder : public Glib::Object
_CLASS_GOBJECT(Builder, GtkBuilder, GTK_BUILDER, Glib::Object, GObject, , , GTKMM_API)
protected:
- _CTOR_DEFAULT
- _IGNORE(gtk_builder_new)
+ Builder();
+ _IGNORE(gtk_builder_new)
public:
/** Creates a new builder object.
@@ -548,18 +548,6 @@ public:
* auto pDialog2 = Gtk::Builder::get_widget_derived<MyDerivedDialog>(refBuilder, "mydialog2", "A storm is
imminent!", true);
* @endcode
*
- * If your derived class overrides vfuncs (virtual functions) or default signal
- * handlers which are part of the wrapped C API, its class name in the XML UI file
- * must have a @a gtkmm__ prefix, for instance
- * @code
- * <object class="gtkmm__GtkDialog" id="mydialog3">
- * @endcode
- * gtkmm__GtkDialog is a subclass of GtkDialog in the GType system. In most
- * respects a GtkSomeClass instance acts identically to a gtkmm__GtkSomeClass
- * instance, but C++ vfuncs and default signal handlers are not called for
- * GtkSomeClass instances. (Signal handlers, connected with signal_some_signal().connect(),
- * are called for both gtkmm__GtkSomeClass and GtkSomeClass instances.)
- *
* @note
* If get_widget_derived() is called more than once for the same widget (the
* same @a name), only the first call will call the widget's constructor.
@@ -642,14 +630,25 @@ public:
_WRAP_METHOD(void set_translation_domain(const Glib::ustring& domain), gtk_builder_set_translation_domain)
_WRAP_METHOD(Glib::ustring get_translation_domain() const, gtk_builder_get_translation_domain)
- //We ignore gtk_builder_get_type_from_name() because it only seems useful when implementing GtkBuildable
for widgets.
+ // We ignore gtk_builder_get_type_from_name() because it only seems useful when implementing GtkBuildable
for widgets.
_IGNORE(gtk_builder_get_type_from_name)
+ // We ignore BuilderScope methods and property because it seems unlikely
+ // that a user of Builder wants to change the scope.
+ _IGNORE(gtk_builder_set_scope, gtk_builder_get_scope)
+ _IGNORE_PROPERTY(scope)
_WRAP_PROPERTY("translation-domain", Glib::ustring)
protected:
Gtk::Widget* get_widget_checked(const Glib::ustring& name, GType type);
GtkWidget* get_cwidget(const Glib::ustring& name);
+
+private:
+ bool no_gtkmm_derived_types {false};
+ void set_no_gtkmm_derived_types(bool status);
+ bool get_no_gtkmm_derived_types() const;
+ friend class GTKMM_API Buildable_Class;
+ friend class GTKMM_API BuilderScope_Class;
};
} // namespace Gtk
diff --git a/gtk/src/buildercscope.ccg b/gtk/src/buildercscope.ccg
new file mode 100644
index 00000000..57b87fdc
--- /dev/null
+++ b/gtk/src/buildercscope.ccg
@@ -0,0 +1,17 @@
+/* Copyright (C) 2020 The gtkmm Development Team
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
diff --git a/gtk/src/buildercscope.hg b/gtk/src/buildercscope.hg
new file mode 100644
index 00000000..188c2c12
--- /dev/null
+++ b/gtk/src/buildercscope.hg
@@ -0,0 +1,50 @@
+/* Copyright (C) 2020 The gtkmm Development Team
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glibmm/object.h>
+#include <gtkmm/builderscope.h>
+
+_DEFS(gtkmm,gtk)
+_PINCLUDE(glibmm/private/object_p.h)
+
+namespace Gtk
+{
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+/** Bindings for Gtk::Builder.
+ *
+ * gtkmm applications probably don't need this class.
+ *
+ * %Gtk::BuilderCScope provides support to Gtk::Builder, primarily
+ * for looking up programming-language-specific values for strings that are
+ * given in a Gtk::Builder UI file.
+ *
+ * @see Gtk::Builder
+ * @newin{3,98}
+ */
+class GTKMM_API BuilderCScope : public Glib::Object, public BuilderScope
+{
+ _CLASS_GOBJECT(BuilderCScope, GtkBuilderCScope, GTK_BUILDER_CSCOPE, Glib::Object, GObject, , , GTKMM_API)
+ _IMPLEMENTS_INTERFACE(BuilderScope)
+
+protected:
+ _CTOR_DEFAULT()
+
+public:
+ _WRAP_CREATE()
+};
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+} // namespace Gtk
diff --git a/gtk/src/builderscope.ccg b/gtk/src/builderscope.ccg
new file mode 100644
index 00000000..663d80ee
--- /dev/null
+++ b/gtk/src/builderscope.ccg
@@ -0,0 +1,66 @@
+/* Copyright (C) 2020 The gtkmm Development Team
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+#include <gtkmm/builder.h>
+
+namespace Gtk
+{
+
+// Allow GtkBuilder to instantiate a gtkmm derived GType instead of the regular
+// GTK GType, so we can, for instance, use our vfuncs and default signal handlers.
+// static
+GType BuilderScope_Class::get_type_from_name_vfunc_callback(
+ GtkBuilderScope* self, GtkBuilder* builder, const char* type_name)
+{
+ if (!type_name)
+ return G_TYPE_INVALID;
+
+ GType gtype = G_TYPE_INVALID;
+
+ // If a TreeModel (such as ListStore or TreeStore) is being built,
+ // Buildable_Class may have requested no search for gtkmm-derived types.
+ // See https://bugzilla.gnome.org/show_bug.cgi?id=742637
+ const auto obj = dynamic_cast<Builder*>(
+ Glib::ObjectBase::_get_current_wrapper((GObject*)builder));
+ if (!(obj && obj->no_gtkmm_derived_types))
+ {
+ // See if there is a gtkmm version of the gclass:
+ Glib::ustring classname_prefixed ("gtkmm__"); // gtkmm uses a prefix
+ classname_prefixed += type_name;
+
+ gtype = g_type_from_name(classname_prefixed.c_str());
+ }
+
+ if (gtype == G_TYPE_INVALID) // If it's not a registered typename
+ {
+ const auto base = static_cast<BaseClassType*>(
+ // Get the parent interface of the interface (The original underlying C interface).
+ g_type_interface_peek_parent(
+ // Get the interface.
+ g_type_interface_peek(G_OBJECT_GET_CLASS(self), CppObjectType::get_type())));
+
+ // Call the original underlying C function.
+ if (base && base->get_type_from_name)
+ gtype = (*base->get_type_from_name)(self, builder, type_name);
+ else // If that's not possible, just use the normal GType.
+ gtype = g_type_from_name(type_name);
+ }
+
+ return gtype;
+}
+
+} // namespace Gtk
diff --git a/gtk/src/builderscope.hg b/gtk/src/builderscope.hg
new file mode 100644
index 00000000..08abd3fe
--- /dev/null
+++ b/gtk/src/builderscope.hg
@@ -0,0 +1,65 @@
+/* Copyright (C) 2020 The gtkmm Development Team
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+_CONFIGINCLUDE(gtkmmconfig.h)
+
+#include <glibmm/interface.h>
+
+_DEFS(gtkmm,gtk)
+_PINCLUDE(glibmm/private/interface_p.h)
+_PINCLUDE(gtk/gtk.h)
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+extern "C"
+{
+typedef struct _GtkBuilderScopeInterface GtkBuilderScopeInterface;
+}
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+namespace Gtk
+{
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+/** Bindings for Gtk::Builder.
+ *
+ * gtkmm applications probably don't need this interface.
+ *
+ * %Gtk::BuilderScope is an interface to provide support to Gtk::Builder, primarily
+ * for looking up programming-language-specific values for strings that are
+ * given in a Gtk::Builder UI file.
+ *
+ * @see Gtk::Builder
+ * @newin{3,98}
+ */
+class GTKMM_API BuilderScope : public Glib::Interface
+{
+ _CLASS_INTERFACE(BuilderScope, GtkBuilderScope, GTK_BUILDER_SCOPE, GtkBuilderScopeInterface, , , GTKMM_API)
+
+protected:
+
+#m4begin
+dnl Custom-coded vfunc:
+dnl
+ _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
+ klass->get_type_from_name = &get_type_from_name_vfunc_callback;
+ _SECTION(SECTION_PH_VFUNCS)
+ static GType get_type_from_name_vfunc_callback(
+ GtkBuilderScope* self, GtkBuilder* builder, const char* type_name);
+ _POP()
+#m4end
+};
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+} // namespace Gtk
diff --git a/gtk/src/filelist.am b/gtk/src/filelist.am
index 353613cd..5963a1df 100644
--- a/gtk/src/filelist.am
+++ b/gtk/src/filelist.am
@@ -32,6 +32,8 @@ gtkmm_files_any_hg = \
boxlayout.hg \
buildable.hg \
builder.hg \
+ buildercscope.hg \
+ builderscope.hg \
button.hg \
calendar.hg \
cellarea.hg \
diff --git a/tests/builder/main.cc b/tests/builder/main.cc
index 3d8d096b..68a13db8 100644
--- a/tests/builder/main.cc
+++ b/tests/builder/main.cc
@@ -169,6 +169,15 @@ public:
m_pStandardButton->add_destroy_notify_callback(nullptr, on_managed_button_deleted);
}
+ // A default signal handler in Gtk::Window shall be called if the
+ // class name in the UI file is GtkWindow, although the real GType name
+ // is gtkmm__GtkWindow. https://gitlab.gnome.org/GNOME/gtkmm/-/issues/61
+ bool on_close_request() override
+ {
+ std::cout << "MainWindow::on_close_request()" << std::endl;
+ return Gtk::Window::on_close_request(); // Call the base class
+ }
+
virtual ~MainWindow()
{
std::cout << "MainWindow::dtor" << std::endl;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]