/* * moocpp/gobjptr.h * * Copyright (C) 2004-2016 by Yevgen Muntyan * * This file is part of medit. medit 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. * * You should have received a copy of the GNU Lesser General Public * License along with medit. If not, see . */ #pragma once #include "moocpp/gobjrawptr.h" #include "moocpp/grefptr.h" #include "moocpp/gobjectutils.h" namespace moo { /////////////////////////////////////////////////////////////////////////////////////////// // // gobj_ptr // template class gobj_ptr { using ref_type = gobj_ref; static_assert(gobjinfo::is_gobject, "Not a GObject"); public: gobj_ptr() {} gobj_ptr(Object* obj, ref_transfer policy) { assign(obj, policy); } gobj_ptr(const nullptr_t&) : gobj_ptr() { } static gobj_ptr wrap_new(Object* obj) { return gobj_ptr(obj, ref_transfer::take_ownership); } static gobj_ptr wrap(Object* obj) { return gobj_ptr(obj, ref_transfer::make_copy); } ~gobj_ptr() { reset(); } void ref(Object* obj) { assign(obj, ref_transfer::make_copy); } void set(Object* obj) { assign(obj, ref_transfer::make_copy); } void set_new(Object* obj) { assign(obj, ref_transfer::take_ownership); } Object* release() { auto* tmp = gobj(); m_ref._set_gobj(nullptr); return tmp; } void reset() { auto* tmp = gobj(); if (tmp) { m_ref._set_gobj(nullptr); g_object_unref(tmp); } } // Implicit conversion to non-const Object* is dangerous because there is a lot // of code still which frees/steals objects directly. For example: // FooObject* tmp = x->s; // x->s = NULL; // g_object_unref (tmp); operator const Object* () const { return gobj(); } operator ref_type*() const { return m_ref.self(); } ref_type* operator->() const { return m_ref.self(); } ref_type& operator*() { return m_ref; } const ref_type& operator*() const { return m_ref; } // These are nasty. Because of ref_type* conversion this can be converted to void*, // which in turn can be passed to g_object_ref or g_free, etc. operator void*() const = delete; operator const void*() const = delete; Object* gobj() const { return m_ref.gobj(); } Object** pp() { return m_ref._pp(); } template Super* gobj() const { return gobj_is_subclass::down_cast(m_ref.gobj()); } template operator const Super* () const { return gobj(); } template operator gobj_ptr () const { return gobj_ptr::wrap (gobj ()); } operator bool() const { return gobj() != nullptr; } bool operator!() const { return gobj() == nullptr; } gobj_ptr(const gobj_ptr& other) : gobj_ptr() { ref(other.gobj()); } gobj_ptr& operator=(const gobj_ptr& other) { ref(other.gobj()); return *this; } gobj_ptr(gobj_ptr&& other) : gobj_ptr() { m_ref._set_gobj(other.gobj()); other.m_ref._set_gobj(nullptr); } gobj_ptr& operator=(const nullptr_t&) { reset(); return *this; } gobj_ptr& operator=(gobj_ptr&& other) { if (gobj() != other.gobj()) { assign(other.gobj(), ref_transfer::take_ownership); other.m_ref._set_gobj(nullptr); } return *this; } private: void assign(Object* obj, ref_transfer policy) { g_assert(!obj || G_IS_OBJECT(obj)); if (gobj() != obj) { Object* tmp = gobj(); m_ref._set_gobj(obj); if (obj) { if (policy == ref_transfer::make_copy) g_object_ref(obj); else if (g_object_is_floating(obj)) g_object_ref_sink(obj); } if (tmp) g_object_unref(tmp); } } private: mutable gobj_ref m_ref; }; template inline gobj_ptr wrap_new(Object *obj) { return gobj_ptr::wrap_new(obj); } template inline gobj_ptr wrap(Object* obj) { return gobj_ptr::wrap(obj); } template inline gobj_ptr wrap(const gobj_raw_ptr& obj) { return gobj_ptr::wrap(obj); } template inline gobj_ref wrap (Object& obj) { return *wrap (&obj); } template inline gobj_ptr create_gobj(GType obj_type, Args&& ...args) { return wrap_new(reinterpret_cast(g_object_new(obj_type, std::forward(args)...))); } template inline gobj_ptr create_gobj(Args&& ...args) { // object_g_type() will produce a compiler error if the type wasn't registered return create_gobj(gobjinfo::object_g_type(), std::forward(args)...); } template inline gobj_ptr create_gobj() { // object_g_type() will produce a compiler error if the type wasn't registered return create_gobj(gobjinfo::object_g_type(), nullptr); } template Object* up_cast (Super* o) { return G_TYPE_CHECK_INSTANCE_CAST ((o), gobjinfo::object_g_type(), Object); } } // namespace moo template void g_object_unref(const moo::gobj_ptr&) = delete; template void g_free(const moo::gobj_ptr&) = delete; template inline bool operator==(const moo::gobj_ptr& p, const nullptr_t&) { return p.gobj() == nullptr; } template inline bool operator==(const nullptr_t&, const moo::gobj_ptr& p) { return p.gobj() == nullptr; } template inline bool operator==(const moo::gobj_ptr& p1, const moo::gobj_ptr& p2) { return p1.gobj() == p2.gobj(); } template inline bool operator==(const moo::gobj_ptr& p1, const Y* p2) { return p1.gobj() == p2; } template inline bool operator==(const X* p1, const moo::gobj_ptr& p2) { return p1 == p2.gobj(); } template inline bool operator==(const moo::gobj_ptr& p1, const moo::gobj_raw_ptr& p2) { return p1.gobj() == p2.gobj(); } template inline bool operator==(const moo::gobj_raw_ptr& p1, const moo::gobj_ptr& p2) { return p1.gobj() == p2.gobj(); } template bool operator!=(const moo::gobj_ptr& p1, const moo::gobj_ptr& p2) { return !(p1 == p2); } template bool operator!=(const moo::gobj_ptr& p1, const Y& p2) { return !(p1 == p2); } template bool operator!=(const X& p1, const moo::gobj_ptr& p2) { return !(p1 == p2); } template bool operator==(const moo::gobj_ptr& p1, int) = delete; template bool operator==(int, const moo::gobj_ptr& p2) = delete; template bool operator!=(const moo::gobj_ptr& p1, int) = delete; template bool operator!=(int, const moo::gobj_ptr& p2) = delete;