+2.51.5
+
+Gio:
+* Application: get_default(): Correct the reference counting.
+ (KJell Ahlstedt) Bug #779936 (James Legg)
+* Add PropertyAction.
+ (Kjell Ahlstedt)
+
+Glib:
+* Remove Glib::unconst() because it is unused and unnecessary.
+ (Kjell Ahlstedt)
+* Variant: Add template specialization for std::tuple,
+ and a test.
+ (Alexander Rössler, Kjell Ahlstedt) Bug #777791
+
+
2.51.2 (unstable):
Distro packagers should probably not package this yet.
## 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/>.
-AC_INIT([glibmm], [2.51.2],
+AC_INIT([glibmm], [2.51.5],
[http://bugzilla.gnome.org/enter_bug.cgi?product=glibmm],
[glibmm], [http://www.gtkmm.org/])
AC_PREREQ([2.59])
#include <giomm/permission.h>
#include <giomm/pollableinputstream.h>
#include <giomm/pollableoutputstream.h>
+#include <giomm/propertyaction.h>
#include <giomm/proxy.h>
#include <giomm/proxyaddress.h>
#include <giomm/proxyresolver.h>
/// Unsets any existing default application.
static void unset_default();
- _WRAP_METHOD(static Glib::RefPtr<Application> get_default(), g_application_get_default)
+ _WRAP_METHOD(static Glib::RefPtr<Application> get_default(), g_application_get_default, refreturn)
_WRAP_METHOD(void mark_busy(), g_application_mark_busy)
_WRAP_METHOD(void unmark_busy(), g_application_unmark_busy)
permission.hg \
pollableinputstream.hg \
pollableoutputstream.hg \
+ propertyaction.hg \
proxy.hg \
proxyaddress.hg \
proxyresolver.hg \
--- /dev/null
+/* Copyright (C) 2017 The giomm 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 <gio/gio.h>
+
+namespace Gio
+{
+
+PropertyAction::PropertyAction(const Glib::ustring& name,
+ const Glib::PropertyProxy_Base& property_proxy, bool invert_boolean)
+:
+_CONSTRUCT("name", name.c_str(), "object", property_proxy.get_object()->gobj(),
+ "property-name", property_proxy.get_name(),
+ "invert-boolean", invert_boolean)
+{
+}
+
+} // namespace Gio
--- /dev/null
+/* Copyright (C) 2017 The giomm 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 <glibmm/refptr.h>
+#include <giomm/action.h>
+
+_DEFS(giomm,gio)
+_PINCLUDE(glibmm/private/object_p.h)
+
+namespace Gio
+{
+/** An Action reflecting a Glib::Object property.
+ *
+ * A %PropertyAction is a way to get an Action with a state value
+ * reflecting and controlling the value of a Glib::Object property.
+ *
+ * The state of the action will correspond to the value of the property.
+ * Changing it will change the property (assuming the requested value
+ * matches the requirements as specified in the GParamSpec, used when the
+ * property was installed).
+ *
+ * Only the most common types are presently supported. Booleans are
+ * mapped to booleans, strings to strings, signed/unsigned integers to
+ * int32/uint32 and floats and doubles to doubles.
+ *
+ * If the property is an enum then the state will be string-typed and
+ * conversion will automatically be performed between the enum value and
+ * "nick" string as per the GEnumValue table.
+ *
+ * Flags types are not currently supported.
+ *
+ * Properties of object types, boxed types and pointer types are not
+ * supported and probably never will be.
+ *
+ * Properties of Glib::Variant types are not currently supported.
+ *
+ * If the property is boolean-valued then the action will have a nullptr
+ * parameter type, and activating the action (with no parameter) will
+ * toggle the value of the property.
+ *
+ * In all other cases, the parameter type will correspond to the type of
+ * the property.
+ *
+ * The general idea here is to reduce the number of locations where a
+ * particular piece of state is kept (and therefore has to be synchronised
+ * between). %PropertyAction does not have a separate state that is kept
+ * in sync with the property value -- its state is the property value.
+ *
+ * For example, it might be useful to create an Action corresponding to
+ * property_visible_child_name() of a Gtk::Stack so that the current
+ * page can be switched from a menu. The active radio indication in the
+ * menu is then directly determined from the active page of the Gtk::Stack.
+ *
+ * An anti-example would be binding property_active_id() on a Gtk::ComboBox.
+ * This is because the state of the combobox itself is probably uninteresting
+ * and is actually being used to control something else.
+ *
+ * Another anti-example would be to bind to property_visible_child_name()
+ * of a Gtk::Stack if this value is actually stored in Gio::Settings.
+ * In that case, the real source of the value is
+ * Gio::Settings. If you want an Action to control a setting stored in
+ * Gio::Settings, see Gio::Settings::create_action() instead, and possibly
+ * combine its use with Gio::Settings::bind().
+ *
+ * @newin{2,52}
+ */
+class PropertyAction : public Glib::Object, public Action
+{
+ _CLASS_GOBJECT(PropertyAction, GPropertyAction, G_PROPERTY_ACTION, Glib::Object, GObject)
+ _IMPLEMENTS_INTERFACE(Action)
+
+protected:
+ PropertyAction(const Glib::ustring& name, const Glib::PropertyProxy_Base& property_proxy,
+ bool invert_boolean = false);
+
+public:
+ /** Creates an Action corresponding to the value of property @a property_proxy.
+ *
+ * The property must be existent and readable and writable (and not construct-only).
+ *
+ * This function takes a reference on the property's object and doesn't
+ * release it until the action is destroyed.
+ *
+ * @param name The name of the action to create.
+ * @param property_proxy The property to bind.
+ * @param invert_boolean If <tt>true</tt>, the state of the action will be
+ * the negation of the property value, provided the property is boolean.
+ * @return A new %PropertyAction.
+ *
+ * @newin{2,52}
+ */
+ _WRAP_CREATE(const Glib::ustring& name, const Glib::PropertyProxy_Base& property_proxy,
+ bool invert_boolean = false)
+
+ _WRAP_PROPERTY("name", Glib::ustring, newin "2,52")
+ _WRAP_PROPERTY("parameter-type", Glib::VariantType, newin "2,52")
+ _WRAP_PROPERTY("enabled", bool, newin "2,52")
+ _WRAP_PROPERTY("state-type", Glib::VariantType, newin "2,52")
+ _WRAP_PROPERTY("state", Glib::VariantBase, newin "2,52")
+ //_WRAP_PROPERTY("object", Glib::ObjectBase) // write-only, construct-only
+ //_WRAP_PROPERTY("property-name", Glib::ustring) // write-only, construct-only
+ _WRAP_PROPERTY("invert-boolean", bool, newin "2,52")
+
+ // There are no methods (apart from ctor and create), signals or vfuncs.
+};
+
+} // namespace Gio
return std::unique_ptr<T[], decltype(&g_free)>(p, &g_free);
}
-// TODO: Deprecate this? We don't use it ourselves.
-/** Removes the const nature of a ptr
- *
- */
-template <class T>
-inline T*
-unconst(const T* t)
-{
- return const_cast<T*>(t);
-}
-
// Convert const gchar* to ustring, while treating NULL as empty string.
inline Glib::ustring
convert_const_gchar_ptr_to_ustring(const char* str)
#include <utility>
#include <vector>
#include <map>
+#include <tuple>
#include <stdexcept>
#include <typeinfo>
VariantIter get_iter() const;
};
+/** Specialization of Variant containing a tuple.
+ * @newin{2,52}
+ * @ingroup Variant
+ */
+template <class... Types>
+class Variant<std::tuple<Types...>> : public VariantContainerBase
+{
+public:
+ using CppContainerType = std::tuple<Types...>;
+
+ /// Default constructor
+ Variant<std::tuple<Types...>>()
+ : VariantContainerBase()
+ {}
+
+ /** GVariant constructor.
+ * @param castitem The GVariant to wrap.
+ * @param take_a_reference Whether to take an extra reference of the GVariant
+ * or not (not taking one could destroy the GVariant with the wrapper).
+ */
+ explicit Variant<std::tuple<Types...>>(GVariant* castitem, bool take_a_reference = false)
+ : VariantContainerBase(castitem, take_a_reference)
+ {}
+
+ /** Creates a new Variant containing a tuple.
+ * @param data The tuple to use for creation.
+ * @return The new Variant holding a tuple.
+ * @newin{2,52}
+ */
+ static Variant<std::tuple<Types...>> create(const std::tuple<Types...>& data);
+
+ /** Gets the VariantType.
+ * @return The VariantType.
+ * @newin{2,52}
+ */
+ static const VariantType& variant_type() G_GNUC_CONST;
+
+ /** Gets a specific element from the tuple.
+ * It is an error if @a index is greater than or equal to the number of
+ * elements in the tuple. See VariantContainerBase::get_n_children().
+ *
+ * @param index The index of the element.
+ * @return The tuple element at index @a index.
+ * @throw std::out_of_range
+ * @newin{2,52}
+ */
+ template<class T>
+ T get_child(gsize index) const;
+
+ template<class T>
+ Variant<T> get_child_variant(gsize index) const;
+
+ /** Gets the tuple of the Variant.
+ * @return The tuple.
+ * @newin{2,52}
+ */
+ std::tuple<Types...> get() const;
+
+ /** Gets a VariantIter of the Variant.
+ * @return The VariantIter.
+ * @newin{2,52}
+ */
+ VariantIter get_iter() const;
+};
+
} // namespace Glib
return VariantContainerBase::get_iter(variant_type());
}
+/*---------------------Variant<std::tuple<class... Types>> --------------------*/
+
+// static
+template <class... Types>
+const VariantType& Variant<std::tuple<Types...>>::variant_type()
+{
+ std::vector<VariantType> types;
+ auto expander = [&types](const VariantType &type) mutable -> int
+ {
+ types.push_back(type);
+ return 0;
+ };
+
+ // expands the variadic template parameters
+ using swallow = int[]; // ensures left to right order
+ swallow{(expander(Variant<Types>::variant_type()))...};
+ static auto type = VariantType::create_tuple(types);
+
+ return type;
+}
+
+namespace detail
+{
+template <class Tuple, std::size_t... Is>
+void expand_tuple(std::vector<VariantBase> &variants, const Tuple & t,
+ std::index_sequence<Is...>)
+{
+ using swallow = int[]; // ensures left to right order
+ auto expander = [&variants](const VariantBase &variant) -> int
+ {
+ variants.push_back(variant);
+ return 0;
+ };
+ (void)swallow {(expander(Variant<typename std::tuple_element<Is, Tuple>::type>::create(std::get<Is>(t))))...};
+}
+} // namespace detail
+
+template <class... Types>
+Variant<std::tuple<Types...>>
+Variant<std::tuple<Types...>>::create(const std::tuple<Types...>& data)
+{
+ // create a vector containing all tuple values as variants
+ std::vector<Glib::VariantBase> variants;
+ detail::expand_tuple(variants, data, std::index_sequence_for<Types...>{});
+
+ using var_ptr = GVariant*;
+ var_ptr* const var_array = new var_ptr[sizeof... (Types)];
+
+ for (std::vector<VariantBase>::size_type i = 0; i < variants.size(); i++)
+ var_array[i] = const_cast<GVariant*>(variants[i].gobj());
+
+ Variant<std::tuple<Types...>> result = Variant<std::tuple<Types...>>(
+ g_variant_new_tuple(var_array, variants.size()));
+
+ return result;
+}
+
+template <class... Types>
+template <class T>
+T Variant<std::tuple<Types...>>::get_child(gsize index) const
+{
+ Variant<T> entry;
+ VariantContainerBase::get_child(entry, index);
+ return entry.get();
+}
+
+template <class... Types>
+template <class T>
+Variant<T> Variant<std::tuple<Types...>>::get_child_variant(gsize index) const
+{
+ Variant<T> entry;
+ VariantContainerBase::get_child(entry, index);
+ return entry;
+}
+
+namespace detail
+{
+// swallows any argument
+template <class T>
+constexpr int any_arg(T&& arg)
+{
+ (void)arg;
+ return 0;
+}
+
+template <class Tuple, std::size_t... Is>
+void assign_tuple(std::vector<VariantBase> &variants, Tuple & t, std::index_sequence<Is...>)
+{
+ int i = 0;
+ using swallow = int[]; // ensures left to right order
+ (void)swallow {(any_arg(std::get<Is>(t) = VariantBase::cast_dynamic<Variant<typename std::tuple_element<Is, Tuple>::type > >(variants[i++]).get()))...};
+}
+} // namespace detail
+
+template <class... Types>
+std::tuple<Types...> Variant<std::tuple<Types...>>::get() const
+{
+ std::tuple<Types...> data;
+ int i = 0;
+
+ std::vector<VariantBase> variants;
+ using swallow = int[]; // ensures left to right order
+ auto expander = [&variants, &i](const VariantBase &variant) -> int
+ {
+ variants.push_back(variant);
+ return i++;
+ };
+ swallow{(expander(get_child_variant<Types>(i)))...};
+ detail::assign_tuple(variants, data, std::index_sequence_for<Types...>{});
+
+ return data;
+}
+
+template< class... Types>
+VariantIter Variant<std::tuple<Types...>>::get_iter() const
+{
+ const auto type = variant_type();
+ return VariantContainerBase::get_iter(type);
+}
+
} // namespace Glib
static void test_variant_floating();
static void test_dynamic_cast();
+namespace
+{
+
+int test_tuple()
+{
+ using TupleType = std::tuple<guint16, Glib::ustring, bool>;
+ using MapType = std::map<guint16, TupleType>;
+ bool result_ok = true;
+
+ // First tuple
+ const guint16 q1 = 2;
+ const Glib::ustring s1 = "Hi there";
+ const bool b1 = false;
+ auto t1 = std::make_tuple(q1, s1, b1);
+ auto tuple1_variant = Glib::Variant<TupleType>::create(t1);
+
+ // Second tuple
+ const guint16 q2 = 3;
+ const Glib::ustring s2 = "Hello";
+ const bool b2 = true;
+ auto t2 = std::make_tuple(q2, s2, b2);
+ auto tuple2_variant = Glib::Variant<TupleType>::create(t2);
+
+ // Insert the tuples in a map.
+ MapType m;
+ m[4] = t1;
+ m[5] = t2;
+ auto map_variant = Glib::Variant<MapType>::create(m);
+
+ std::string type_string = tuple1_variant.variant_type().get_string();
+ ostr << "Type string of tuple1: " << type_string << std::endl;
+ result_ok &= type_string == "(qsb)";
+
+ type_string = tuple2_variant.get_type_string();
+ ostr << "Type string of tuple2: " << type_string << std::endl;
+ result_ok &= type_string == "(qsb)";
+
+ type_string = map_variant.variant_type().get_string();
+ ostr << "Type string of map of tuples: " << type_string << std::endl;
+ result_ok &= map_variant.get_type_string() == "a{q(qsb)}";
+
+ // Extract from the map of tuples.
+ std::pair<guint16, TupleType> child0 = map_variant.get_child(0);
+ ostr << "Index of first map entry: " << child0.first << std::endl;
+ result_ok &= child0.first == 4;
+ auto extracted_tuple = child0.second;
+ auto q3 = std::get<guint16>(extracted_tuple);
+ auto s3 = std::get<Glib::ustring>(extracted_tuple);
+ auto b3 = std::get<bool>(extracted_tuple);
+ ostr << "Extracted tuple1 from map: (" << q3 << ", " << s3 << ", " << b3 << ")" << std::endl;
+ result_ok &= q3 == q1 && s3 == s1 && b3 == b1;
+
+ // Extract from a tuple.
+ auto q4 = tuple2_variant.get_child<guint16>(0);
+ auto s4 = tuple2_variant.get_child_variant<Glib::ustring>(1).get();
+ auto b4 = std::get<bool>(tuple2_variant.get());
+ ostr << "Extracted tuple2: (" << q4 << ", " << s4 << ", " << b4 << ")" << std::endl;
+ result_ok &= q4 == q2 && s4 == s2 && b4 == b2;
+
+ return result_ok ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+} // anonymous namespace
+
int
main(int, char**)
{
test_variant_floating();
test_dynamic_cast();
- return EXIT_SUCCESS;
+ return test_tuple();
}
// Test casting of multiple types to a ustring: