/* Copyright 2010 The glibmm 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, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include namespace Glib { VariantBase::VariantBase(GVariant* castitem, bool make_a_copy /* = false */) { if (castitem) { if (g_variant_is_floating(castitem)) { g_variant_ref_sink (castitem); } if (make_a_copy) { g_variant_ref (castitem); } } gobject_ = castitem; } void VariantBase::get_normal_form(VariantBase& result) const { GVariant* const g_value = g_variant_get_normal_form(const_cast(gobj())); //The C function never returns NULL, according to its docuemenation, //so we don't need a bool return value. result.init(g_value); // g_value is already referenced. } void VariantBase::byteswap(VariantBase& result) const { GVariant* const g_value = g_variant_byteswap(const_cast(gobj())); result.init(g_value); // g_value is already referenced. } VariantStringBase::VariantStringBase() : VariantBase() { } VariantStringBase::VariantStringBase(GVariant* castitem, bool take_a_reference) : VariantBase(castitem, take_a_reference) { } //static void VariantStringBase::create_object_path(VariantStringBase& output, const std::string& object_path) { GVariant* result = 0; result = g_variant_new_object_path(object_path.c_str()); g_variant_ref_sink(result); output.init(result); } //static void VariantStringBase::create_signature(VariantStringBase& output, const std::string& signature) { GVariant* result = 0; result = g_variant_new_signature(signature.c_str()); g_variant_ref_sink(result); output.init(result); } VariantContainerBase::VariantContainerBase() : VariantBase() { } VariantContainerBase::VariantContainerBase(GVariant* castitem, bool take_a_reference) : VariantBase(castitem, take_a_reference) { } //static VariantContainerBase VariantContainerBase::create_tuple(const std::vector& children) { typedef GVariant* var_ptr; var_ptr* const var_array = new var_ptr[children.size()]; for(std::vector::size_type i = 0; i < children.size(); i++) { var_array[i] = const_cast(children[i].gobj()); } VariantContainerBase result = VariantContainerBase(g_variant_new_tuple( var_array, children.size())); g_variant_ref_sink(result.gobj()); delete[] var_array; return result; } //static VariantContainerBase VariantContainerBase::create_tuple(const VariantBase& child) { std::vector vec; vec.push_back(child); return create_tuple(vec); } //static VariantContainerBase VariantContainerBase::create_maybe(const VariantType& child_type, const VariantBase& child) { GVariant* g_variant = g_variant_new_maybe(child_type.gobj(), const_cast(child.gobj())); VariantContainerBase result = VariantContainerBase(g_variant); // Remove the floating reference (since it is newly created). g_variant_ref_sink(result.gobj()); return result; } void VariantContainerBase::get_child(VariantBase& child, gsize index) const { if(index >= g_variant_n_children(gobject_)) throw std::out_of_range( "VariantContainerBase::get(): Index out of bounds."); GVariant* const gvariant = g_variant_get_child_value(gobject_, index); child.init(gvariant); } // VariantContainerBase has no method variant_type() template<> VariantContainerBase VariantBase::cast_dynamic(const VariantBase& v) throw(std::bad_cast) { if(!v.gobj()) { return VariantContainerBase(); } if(v.get_type().is_container()) { return VariantContainerBase(const_cast(v.gobj()), true); } else { //std::cerr << "vtype=" << v.get_type_string() << std::endl; throw std::bad_cast(); } } bool VariantContainerBase::get_maybe(VariantBase& maybe) const { GVariant* const g_value = g_variant_get_maybe(const_cast(gobj())); if(g_value) { maybe.init(g_value); // g_value is already referenced. return true; } else return false; } /****************** Specializations ***********************************/ void VariantBase::init(const GVariant* cobject, bool take_a_reference) { if(gobject_) g_variant_unref(gobject_); gobject_ = const_cast(cobject); if(take_a_reference) g_variant_ref(gobject_); } Variant::Variant() : VariantContainerBase() { } Variant::Variant(GVariant* castitem, bool take_a_reference) : VariantContainerBase(castitem, take_a_reference) { } // static const VariantType& Variant::variant_type() { return VARIANT_TYPE_VARIANT; } Variant Variant::create(const VariantBase& data) { Variant result = Variant(g_variant_new_variant(const_cast(data.gobj()))); // Remove the floating reference (since it is newly created). g_variant_ref_sink(result.gobj()); return result; } void Variant::get(VariantBase& variant) const { GVariant* const gvariant = g_variant_get_variant(gobject_); variant.init(gvariant); } Variant::Variant() : VariantStringBase() { } Variant::Variant(GVariant* castitem, bool take_a_reference) : VariantStringBase(castitem, take_a_reference) { } // static const VariantType& Variant::variant_type() { return VARIANT_TYPE_STRING; } Variant Variant::create(const Glib::ustring& data) { Variant result = Variant(g_variant_new_string(data.c_str())); // Remove the floating reference (since it is newly created). g_variant_ref_sink(result.gobj()); return result; } Glib::ustring Variant::get() const { return convert_const_gchar_ptr_to_ustring(g_variant_get_string(gobject_, 0)); } // Variant makes sense for multiple types. // See http://library.gnome.org/devel/glib/unstable/glib-GVariant.html#g-variant-get-string template<> Variant VariantBase::cast_dynamic< Variant >(const VariantBase& v) throw(std::bad_cast) { if(!v.gobj()) { return Variant(); } const VariantType vtype = v.get_type(); if( vtype.equal(VARIANT_TYPE_STRING) || vtype.equal(VARIANT_TYPE_OBJECT_PATH) || vtype.equal(VARIANT_TYPE_SIGNATURE) ) { return Variant(const_cast(v.gobj()), true); } else { //std::cerr << "vtype=" << v.get_type_string() << std::endl; throw std::bad_cast(); } } Variant::Variant() : VariantStringBase() { } Variant::Variant(GVariant* castitem, bool take_a_reference) : VariantStringBase(castitem, take_a_reference) { } // static const VariantType& Variant::variant_type() { return VARIANT_TYPE_BYTESTRING; } Variant Variant::create(const std::string& data) { Variant result = Variant(g_variant_new_bytestring(data.c_str())); // Remove the floating reference (since it is newly created). g_variant_ref_sink(result.gobj()); return result; } // Variant makes sense for multiple types. // See http://library.gnome.org/devel/glib/unstable/glib-GVariant.html#g-variant-get-string template<> Variant VariantBase::cast_dynamic< Variant >(const VariantBase& v) throw(std::bad_cast) { if(!v.gobj()) { return Variant(); } const VariantType vtype = v.get_type(); if( vtype.equal(VARIANT_TYPE_STRING) || vtype.equal(VARIANT_TYPE_BYTESTRING) || vtype.equal(VARIANT_TYPE_OBJECT_PATH) || vtype.equal(VARIANT_TYPE_SIGNATURE) ) { return Variant(const_cast(v.gobj()), true); } else { //std::cerr << "vtype=" << v.get_type_string() << std::endl; throw std::bad_cast(); } } std::string Variant::get() const { const VariantType vtype = get_type(); const char* pch = 0; if(vtype.equal(VARIANT_TYPE_BYTESTRING)) pch = g_variant_get_bytestring(gobject_); else //g_variant_get_string() cna handle strings, object paths, and signatures. pch = g_variant_get_string(gobject_, 0); return convert_const_gchar_ptr_to_stdstring(pch); } typedef std::vector type_vec_ustring; Variant::Variant() : VariantContainerBase() { } Variant::Variant(GVariant* castitem, bool take_a_reference) : VariantContainerBase(castitem, take_a_reference) { } // static const VariantType& Variant::variant_type() { return VARIANT_TYPE_STRING_ARRAY; } Variant Variant::create(const type_vec_ustring& data) { // Get the variant type of the elements. VariantType element_variant_type = Variant::variant_type(); // Get the variant type of the array. VariantType array_variant_type = Variant::variant_type(); // Create a GVariantBuilder to build the array. GVariantBuilder* builder = g_variant_builder_new(array_variant_type.gobj()); // Add the elements of the vector into the builder. for(type_vec_ustring::const_iterator iter = data.begin(); iter < data.end(); iter++) { g_variant_builder_add(builder, element_variant_type.get_string().c_str(), iter->c_str()); } // Create the variant using the builder. Variant result = Variant(g_variant_new( array_variant_type.get_string().c_str(), builder)); // Remove the floating reference (since it is newly created). g_variant_ref_sink(result.gobj()); return result; } Glib::ustring Variant::get_child(gsize index) const { gsize n_elements = 0; const gchar** array = g_variant_get_strv(const_cast(gobj()), &n_elements); if(index >= n_elements) throw std::out_of_range( "Variant< std::vector >::get(): Index out of bounds."); Glib::ustring const result(array[index]); g_free(array); return result; } type_vec_ustring Variant::get() const { gsize n_elements = 0; const gchar** array = g_variant_get_strv(const_cast(gobj()), &n_elements); type_vec_ustring const result(array, array + n_elements); g_free(array); return result; } VariantIter Variant::get_iter() const { // Get the variant type of the elements. VariantType element_variant_type = Variant::variant_type(); // Get the variant type of the array. VariantType array_variant_type = Variant::variant_type(); // Get the GVariantIter. GVariantIter* g_iter = 0; g_variant_get(const_cast(gobj()), array_variant_type.get_string().c_str(), &g_iter); return VariantIter(g_iter); } typedef std::vector type_vec_string; Variant::Variant() : VariantContainerBase() { } Variant::Variant(GVariant* castitem, bool take_a_reference) : VariantContainerBase(castitem, take_a_reference) { } // static const VariantType& Variant::variant_type() { return VARIANT_TYPE_BYTESTRING_ARRAY; } Variant Variant::create(const type_vec_string& data) { // Create a string array to add the strings of the vector to. char** str_array = g_new(char*, data.size() + 1); // Add the elements of the vector into the string array. for(type_vec_string::size_type i = 0; i < data.size(); i++) { str_array[i] = g_strdup(data[i].c_str()); } // Terminate the string array. str_array[data.size()] = NULL; // Create the variant using the builder. Variant result = Variant(g_variant_new_bytestring_array(str_array, data.size())); g_strfreev(str_array); // Remove the floating reference (since it is newly created). g_variant_ref_sink(result.gobj()); return result; } std::string Variant::get_child(gsize index) const { gsize n_elements = 0; const gchar** array = g_variant_get_bytestring_array(const_cast(gobj()), &n_elements); if(index >= n_elements) throw std::out_of_range( "Variant< std::vector >::get(): Index out of bounds."); std::string const result(array[index]); g_free(array); return result; } type_vec_string Variant::get() const { gsize n_elements = 0; const gchar** array = g_variant_get_bytestring_array(const_cast(gobj()), &n_elements); type_vec_string const result(array, array + n_elements); g_free(array); return result; } VariantIter Variant::get_iter() const { // Get the variant type of the elements. const VariantType element_variant_type = Variant::variant_type(); // Get the variant type of the array. const VariantType array_variant_type = Variant::variant_type(); // Get the GVariantIter. GVariantIter* g_iter = 0; g_variant_get(const_cast(gobj()), array_variant_type.get_string().c_str(), &g_iter); return VariantIter(g_iter); } } // namespace Glib