/* Copyright 1998-2002 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
namespace Glib
{
ConstructParams::ConstructParams(const Glib::Class& glibmm_class_)
: glibmm_class(glibmm_class_), n_parameters(0), parameter_names(nullptr), parameter_values(nullptr)
{
}
/*
* The implementation is mostly copied from gobject.c, with some minor tweaks.
* Basically, it looks up each property name to get its GType, and then uses
* G_VALUE_COLLECT() to store the varargs argument in a GValue of the correct
* type.
*
* Note that the property name arguments are assumed to be static string
* literals. No attempt is made to copy the string content. This is no
* different from g_object_new().
*/
ConstructParams::ConstructParams(
const Glib::Class& glibmm_class_, const char* first_property_name, ...)
: glibmm_class(glibmm_class_), n_parameters(0), parameter_names(nullptr), parameter_values(nullptr)
{
va_list var_args;
va_start(var_args, first_property_name);
GObjectClass* const g_class =
static_cast(g_type_class_ref(glibmm_class.get_type()));
unsigned int n_alloced_params = 0;
char* collect_error = nullptr; // output argument of G_VALUE_COLLECT()
for (const char* name = first_property_name; name != nullptr; name = va_arg(var_args, char*))
{
GParamSpec* const pspec = g_object_class_find_property(g_class, name);
if (!pspec)
{
g_warning("Glib::ConstructParams::ConstructParams(): "
"object class \"%s\" has no property named \"%s\"",
g_type_name(glibmm_class.get_type()), name);
break;
}
if (n_parameters >= n_alloced_params) {
n_alloced_params += 8;
parameter_names = g_renew(const char*, parameter_names, n_alloced_params);
parameter_values = g_renew(GValue, parameter_values, n_alloced_params);
}
auto& param_name = parameter_names[n_parameters];
auto& param_value = parameter_values[n_parameters];
param_name = name;
param_value.g_type = 0;
// Fill the GValue with the current vararg, and move on to the next one.
g_value_init(¶m_value, G_PARAM_SPEC_VALUE_TYPE(pspec));
G_VALUE_COLLECT(¶m_value, var_args, 0, &collect_error);
if (collect_error)
{
g_warning("Glib::ConstructParams::ConstructParams(): %s", collect_error);
g_free(collect_error);
g_value_unset(¶m_value);
break;
}
++n_parameters;
}
g_type_class_unref(g_class);
va_end(var_args);
}
ConstructParams::~ConstructParams() noexcept
{
while (n_parameters > 0) {
auto& param_value = parameter_values[--n_parameters];
g_value_unset(¶m_value);
}
g_free(parameter_names);
g_free(parameter_values);
}
/**** Glib::Object_Class ***************************************************/
const Glib::Class&
Object_Class::init()
{
if (!gtype_)
{
class_init_func_ = &Object_Class::class_init_function;
register_derived_type(G_TYPE_OBJECT);
}
return *this;
}
void
Object_Class::class_init_function(void*, void*)
{
}
Object*
Object_Class::wrap_new(GObject* object)
{
return new Object(object);
}
/**** Glib::Object *********************************************************/
// static data
Object::CppClassType Object::object_class_;
Object::Object()
{
// This constructor is ONLY for derived classes that are NOT wrappers of
// derived C objects. For instance, Gtk::Object should NOT use this
// constructor.
// g_warning("Object::Object(): Did you really mean to call this?");
// If Glib::ObjectBase has been constructed with a custom typeid, we derive
// a new GType on the fly. This works because ObjectBase is a virtual base
// class, therefore its constructor is always executed first.
GType object_type = G_TYPE_OBJECT; // the default -- not very useful
if (custom_type_name_ && !is_anonymous_custom_())
{
object_class_.init();
// This creates a type that is derived (indirectly) from GObject.
object_type = object_class_.clone_custom_type(custom_type_name_,
get_custom_interface_classes(), get_custom_class_init_functions(),
get_custom_instance_init_function());
custom_class_init_finished();
}
GObject* const new_object = g_object_new_with_properties(object_type, 0, nullptr, nullptr);
// Connect the GObject and Glib::Object instances.
ObjectBase::initialize(new_object);
}
Object::Object(const Glib::ConstructParams& construct_params)
{
GType object_type = construct_params.glibmm_class.get_type();
// If Glib::ObjectBase has been constructed with a custom typeid, we derive
// a new GType on the fly. This works because ObjectBase is a virtual base
// class, therefore its constructor is always executed first.
if (custom_type_name_ && !is_anonymous_custom_())
{
object_type =
construct_params.glibmm_class.clone_custom_type(custom_type_name_,
get_custom_interface_classes(), get_custom_class_init_functions(),
get_custom_instance_init_function());
custom_class_init_finished();
}
// Create a new GObject with the specified array of construct properties.
// This works with custom types too, since those inherit the properties of
// their base class.
GObject* const new_object =
g_object_new_with_properties(object_type, construct_params.n_parameters, construct_params.parameter_names, construct_params.parameter_values);
// Connect the GObject and Glib::Object instances.
ObjectBase::initialize(new_object);
}
Object::Object(GObject* castitem)
{
// I disabled this check because libglademm really does need to do this.
//(actually it tells libglade to instantiate "gtkmm_" types.
// The 2nd instance bug will be caught elsewhere anyway.
/*
static const char gtkmm_prefix[] = "gtkmm__";
const char *const type_name = G_OBJECT_TYPE_NAME(castitem);
if(strncmp(type_name, gtkmm_prefix, sizeof(gtkmm_prefix) - 1) == 0)
{
g_warning("Glib::Object::Object(GObject*): "
"An object of type '%s' was created directly via g_object_new(). "
"The Object::Object(const Glib::ConstructParams&) constructor "
"should be used instead.\n"
"This could happen if the C instance lived longer than the C++ instance, so that "
"a second C++ instance was created automatically to wrap it. That would be a gtkmm
bug that you should report.",
type_name);
}
*/
// Connect the GObject and Glib::Object instances.
ObjectBase::initialize(castitem);
}
Object::Object(Object&& src) noexcept
: sigc::trackable(std::move(src)), // not actually called because it's a virtual base
ObjectBase(std::move(src)) // not actually called because it's a virtual base
{
// Perhaps trackable's move constructor has not been called. Do its job here.
// (No harm is done if notify_callbacks() is called twice. The second call
// won't do anything.)
src.notify_callbacks();
ObjectBase::initialize_move(src.gobject_, &src);
}
Object&
Object::operator=(Object&& src) noexcept
{
ObjectBase::operator=(std::move(src));
return *this;
}
Object::~Object() noexcept
{
cpp_destruction_in_progress_ = true;
}
/*
RefPtr