/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifndef __COGL_OBJECT_PRIVATE_H #define __COGL_OBJECT_PRIVATE_H #include #include "cogl-types.h" #include "cogl-object.h" #include "cogl-debug.h" /* For compatability until all components have been converted */ typedef struct _CoglObjectClass CoglHandleClass; typedef struct _CoglObject CoglHandleObject; /* XXX: sadly we didn't fully consider when we copied the cairo API * for _set_user_data that the callback doesn't get a pointer to the * instance which is desired in most cases. This means you tend to end * up creating micro allocations for the private data just so you can * pair up the data of interest with the original instance for * identification when it is later destroyed. * * Internally we use a small hack to avoid needing these micro * allocations by actually passing the instance as a second argument * to the callback */ typedef void (*CoglUserDataDestroyInternalCallback) (void *user_data, void *instance); typedef struct _CoglObjectClass { const char *name; void *virt_free; void *virt_unref; } CoglObjectClass; #define COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES 2 typedef struct { CoglUserDataKey *key; void *user_data; CoglUserDataDestroyInternalCallback destroy; } CoglUserDataEntry; /* All Cogl objects inherit from this base object by adding a member: * * CoglObject _parent; * * at the top of its main structure. This structure is initialized * when you call _cogl_#type_name#_object_new (new_object); */ struct _CoglObject { CoglObjectClass *klass; CoglUserDataEntry user_data_entry[ COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES]; GArray *user_data_array; int n_user_data_entries; unsigned int ref_count; }; /* Helper macro to encapsulate the common code for COGL reference counted objects */ #ifdef COGL_OBJECT_DEBUG #define _COGL_OBJECT_DEBUG_NEW(type_name, obj) \ COGL_NOTE (OBJECT, "COGL " G_STRINGIFY (type_name) " NEW %p %i", \ (obj), (obj)->ref_count) #define _COGL_OBJECT_DEBUG_REF(type_name, object) G_STMT_START { \ CoglObject *__obj = (CoglObject *)object; \ COGL_NOTE (OBJECT, "COGL %s REF %p %i", \ (__obj)->klass->name, \ (__obj), (__obj)->ref_count); } G_STMT_END #define _COGL_OBJECT_DEBUG_UNREF(type_name, object) G_STMT_START { \ CoglObject *__obj = (CoglObject *)object; \ COGL_NOTE (OBJECT, "COGL %s UNREF %p %i", \ (__obj)->klass->name, \ (__obj), (__obj)->ref_count - 1); } G_STMT_END #define COGL_OBJECT_DEBUG_FREE(obj) \ COGL_NOTE (OBJECT, "COGL %s FREE %p", \ (obj)->klass->name, (obj)) #else /* !COGL_OBJECT_DEBUG */ #define _COGL_OBJECT_DEBUG_NEW(type_name, obj) #define _COGL_OBJECT_DEBUG_REF(type_name, obj) #define _COGL_OBJECT_DEBUG_UNREF(type_name, obj) #define COGL_OBJECT_DEBUG_FREE(obj) #endif /* COGL_OBJECT_DEBUG */ #define COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ CoglObjectClass _cogl_##type_name##_class; \ static unsigned long _cogl_object_##type_name##_count; \ \ static inline void \ _cogl_object_##type_name##_inc (void) \ { \ _cogl_object_##type_name##_count++; \ } \ \ static inline void \ _cogl_object_##type_name##_dec (void) \ { \ _cogl_object_##type_name##_count--; \ } \ \ static void \ _cogl_object_##type_name##_indirect_free (CoglObject *obj) \ { \ _cogl_##type_name##_free ((Cogl##TypeName *) obj); \ _cogl_object_##type_name##_dec (); \ } \ \ static Cogl##TypeName * \ _cogl_##type_name##_object_new (Cogl##TypeName *new_obj) \ { \ CoglObject *obj = (CoglObject *)&new_obj->_parent; \ obj->ref_count = 0; \ cogl_object_ref (obj); \ obj->n_user_data_entries = 0; \ obj->user_data_array = NULL; \ \ obj->klass = &_cogl_##type_name##_class; \ if (!obj->klass->virt_free) \ { \ _cogl_object_##type_name##_count = 0; \ \ if (_cogl_debug_instances == NULL) \ _cogl_debug_instances = \ g_hash_table_new (g_str_hash, g_str_equal); \ \ obj->klass->virt_free = \ _cogl_object_##type_name##_indirect_free; \ obj->klass->virt_unref = \ _cogl_object_default_unref; \ obj->klass->name = "Cogl"#TypeName, \ \ g_hash_table_insert (_cogl_debug_instances, \ (void *) obj->klass->name, \ &_cogl_object_##type_name##_count); \ \ { code; } \ } \ \ _cogl_object_##type_name##_inc (); \ _COGL_OBJECT_DEBUG_NEW (TypeName, obj); \ return new_obj; \ } #define COGL_OBJECT_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ CoglBool \ cogl_is_##type_name (void *object) \ { \ CoglObject *obj = object; \ \ if (object == NULL) \ return FALSE; \ \ return obj->klass == &_cogl_##type_name##_class; \ } #define COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ CoglBool \ _cogl_is_##type_name (void *object) \ { \ CoglObject *obj = object; \ \ if (object == NULL) \ return FALSE; \ \ return obj->klass == &_cogl_##type_name##_class; \ } #define COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING(type_name) \ \ void * G_GNUC_DEPRECATED \ cogl_##type_name##_ref (void *object) \ { \ if (!cogl_is_##type_name (object)) \ return NULL; \ \ _COGL_OBJECT_DEBUG_REF (TypeName, object); \ \ cogl_handle_ref (object); \ \ return object; \ } \ \ void G_GNUC_DEPRECATED \ cogl_##type_name##_unref (void *object) \ { \ if (!cogl_is_##type_name (object)) \ { \ g_warning (G_STRINGIFY (cogl_##type_name##_unref) \ ": Ignoring unref of Cogl handle " \ "due to type mismatch"); \ return; \ } \ \ _COGL_OBJECT_DEBUG_UNREF (TypeName, object); \ \ cogl_handle_unref (object); \ } #define COGL_OBJECT_DEFINE(TypeName, type_name) \ COGL_OBJECT_DEFINE_WITH_CODE (TypeName, type_name, (void) 0) #define COGL_OBJECT_INTERNAL_DEFINE(TypeName, type_name) \ COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE (TypeName, type_name, (void) 0) /* For temporary compatability */ #define COGL_HANDLE_INTERNAL_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE (TypeName, type_name, code) \ \ static Cogl##TypeName * \ _cogl_##type_name##_handle_new (CoglHandle handle) \ { \ return _cogl_##type_name##_object_new (handle); \ } #define COGL_HANDLE_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ COGL_OBJECT_DEFINE_WITH_CODE (TypeName, type_name, code) \ \ static Cogl##TypeName * \ _cogl_##type_name##_handle_new (CoglHandle handle) \ { \ return _cogl_##type_name##_object_new (handle); \ } #define COGL_HANDLE_DEFINE(TypeName, type_name) \ COGL_HANDLE_DEFINE_WITH_CODE (TypeName, type_name, (void) 0) void _cogl_object_set_user_data (CoglObject *object, CoglUserDataKey *key, void *user_data, CoglUserDataDestroyInternalCallback destroy); void _cogl_object_default_unref (void *obj); #endif /* __COGL_OBJECT_PRIVATE_H */