📄 gobject.c
字号:
/* GObject - GLib Type, Object, Parameter and Signal Library * Copyright (C) 1998-1999, 2000-2001 Tim Janik and Red Hat, Inc. * * 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 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., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. */#include "gobject.h"/* * MT safe */#include "gvaluecollector.h"#include "gsignal.h"#include "gparamspecs.h"#include "gvaluetypes.h"#include "gobjectnotifyqueue.c"#include <string.h>#include <signal.h>#define PREALLOC_CPARAMS (8)/* --- macros --- */#define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)#define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))/* --- signals --- */enum { NOTIFY, LAST_SIGNAL};/* --- properties --- */enum { PROP_NONE};/* --- prototypes --- */static void g_object_base_class_init (GObjectClass *class);static void g_object_base_class_finalize (GObjectClass *class);static void g_object_do_class_init (GObjectClass *class);static void g_object_init (GObject *object);static GObject* g_object_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params);static void g_object_last_unref (GObject *object);static void g_object_real_dispose (GObject *object);static void g_object_finalize (GObject *object);static void g_object_do_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);static void g_object_do_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);static void g_value_object_init (GValue *value);static void g_value_object_free_value (GValue *value);static void g_value_object_copy_value (const GValue *src_value, GValue *dest_value);static void g_value_object_transform_value (const GValue *src_value, GValue *dest_value);static gpointer g_value_object_peek_pointer (const GValue *value);static gchar* g_value_object_collect_value (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags);static gchar* g_value_object_lcopy_value (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags);static void g_object_dispatch_properties_changed (GObject *object, guint n_pspecs, GParamSpec **pspecs);static inline void object_get_property (GObject *object, GParamSpec *pspec, GValue *value);static inline void object_set_property (GObject *object, GParamSpec *pspec, const GValue *value, GObjectNotifyQueue *nqueue);/* --- variables --- */static GQuark quark_closure_array = 0;static GQuark quark_weak_refs = 0;static GParamSpecPool *pspec_pool = NULL;static GObjectNotifyContext property_notify_context = { 0, };static gulong gobject_signals[LAST_SIGNAL] = { 0, };/* --- functions --- */#ifdef G_ENABLE_DEBUG#define IF_DEBUG(debug_type) if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type)G_LOCK_DEFINE_STATIC (debug_objects);static volatile GObject *g_trap_object_ref = NULL;static guint debug_objects_count = 0;static GHashTable *debug_objects_ht = NULL;static voiddebug_objects_foreach (gpointer key, gpointer value, gpointer user_data){ GObject *object = value; g_message ("[%p] stale %s\tref_count=%u", object, G_OBJECT_TYPE_NAME (object), object->ref_count);}static voiddebug_objects_atexit (void){ IF_DEBUG (OBJECTS) { G_LOCK (debug_objects); g_message ("stale GObjects: %u", debug_objects_count); g_hash_table_foreach (debug_objects_ht, debug_objects_foreach, NULL); G_UNLOCK (debug_objects); }}#endif /* G_ENABLE_DEBUG */voidg_object_type_init (void) /* sync with gtype.c */{ static gboolean initialized = FALSE; static const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE, }; static GTypeInfo info = { sizeof (GObjectClass), (GBaseInitFunc) g_object_base_class_init, (GBaseFinalizeFunc) g_object_base_class_finalize, (GClassInitFunc) g_object_do_class_init, NULL /* class_destroy */, NULL /* class_data */, sizeof (GObject), 0 /* n_preallocs */, (GInstanceInitFunc) g_object_init, NULL, /* value_table */ }; static const GTypeValueTable value_table = { g_value_object_init, /* value_init */ g_value_object_free_value, /* value_free */ g_value_object_copy_value, /* value_copy */ g_value_object_peek_pointer, /* value_peek_pointer */ "p", /* collect_format */ g_value_object_collect_value, /* collect_value */ "p", /* lcopy_format */ g_value_object_lcopy_value, /* lcopy_value */ }; GType type; g_return_if_fail (initialized == FALSE); initialized = TRUE; /* G_TYPE_OBJECT */ info.value_table = &value_table; type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &info, &finfo, 0); g_assert (type == G_TYPE_OBJECT); g_value_register_transform_func (G_TYPE_OBJECT, G_TYPE_OBJECT, g_value_object_transform_value); #ifdef G_ENABLE_DEBUG IF_DEBUG (OBJECTS) { debug_objects_ht = g_hash_table_new (g_direct_hash, NULL); g_atexit (debug_objects_atexit); }#endif /* G_ENABLE_DEBUG */}static voidg_object_base_class_init (GObjectClass *class){ GObjectClass *pclass = g_type_class_peek_parent (class); /* reset instance specific fields and methods that don't get inherited */ class->construct_properties = pclass ? g_slist_copy (pclass->construct_properties) : NULL; class->get_property = NULL; class->set_property = NULL;}static voidg_object_base_class_finalize (GObjectClass *class){ GList *list, *node; _g_signals_destroy (G_OBJECT_CLASS_TYPE (class)); g_slist_free (class->construct_properties); class->construct_properties = NULL; list = g_param_spec_pool_list_owned (pspec_pool, G_OBJECT_CLASS_TYPE (class)); for (node = list; node; node = node->next) { GParamSpec *pspec = node->data; g_param_spec_pool_remove (pspec_pool, pspec); PARAM_SPEC_SET_PARAM_ID (pspec, 0); g_param_spec_unref (pspec); } g_list_free (list);}static voidg_object_notify_dispatcher (GObject *object, guint n_pspecs, GParamSpec **pspecs){ G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs);}static voidg_object_do_class_init (GObjectClass *class){ /* read the comment about typedef struct CArray; on why not to change this quark */ quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); quark_weak_refs = g_quark_from_static_string ("GObject-weak-references"); pspec_pool = g_param_spec_pool_new (TRUE); property_notify_context.quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); property_notify_context.dispatcher = g_object_notify_dispatcher; class->constructor = g_object_constructor; class->set_property = g_object_do_set_property; class->get_property = g_object_do_get_property; class->dispose = g_object_real_dispose; class->finalize = g_object_finalize; class->dispatch_properties_changed = g_object_dispatch_properties_changed; class->notify = NULL; gobject_signals[NOTIFY] = g_signal_new ("notify", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (GObjectClass, notify), NULL, NULL, g_cclosure_marshal_VOID__PARAM, G_TYPE_NONE, 1, G_TYPE_PARAM);}voidg_object_class_install_property (GObjectClass *class, guint property_id, GParamSpec *pspec){ g_return_if_fail (G_IS_OBJECT_CLASS (class)); g_return_if_fail (G_IS_PARAM_SPEC (pspec)); if (pspec->flags & G_PARAM_WRITABLE) g_return_if_fail (class->set_property != NULL); if (pspec->flags & G_PARAM_READABLE) g_return_if_fail (class->get_property != NULL); g_return_if_fail (property_id > 0); g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ if (pspec->flags & G_PARAM_CONSTRUCT) g_return_if_fail ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) g_return_if_fail (pspec->flags & G_PARAM_WRITABLE); if (g_param_spec_pool_lookup (pspec_pool, pspec->name, G_OBJECT_CLASS_TYPE (class), FALSE)) { g_warning (G_STRLOC ": class `%s' already contains a property named `%s'", G_OBJECT_CLASS_NAME (class), pspec->name); return; } g_param_spec_ref (pspec); g_param_spec_sink (pspec); PARAM_SPEC_SET_PARAM_ID (pspec, property_id); g_param_spec_pool_insert (pspec_pool, pspec, G_OBJECT_CLASS_TYPE (class)); if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) class->construct_properties = g_slist_prepend (class->construct_properties, pspec); /* for property overrides of construct poperties, we have to get rid * of the overidden inherited construct property */ pspec = g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type_parent (G_OBJECT_CLASS_TYPE (class)), TRUE); if (pspec && pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) class->construct_properties = g_slist_remove (class->construct_properties, pspec);}GParamSpec*g_object_class_find_property (GObjectClass *class, const gchar *property_name){ g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); g_return_val_if_fail (property_name != NULL, NULL); return g_param_spec_pool_lookup (pspec_pool, property_name, G_OBJECT_CLASS_TYPE (class), TRUE);}GParamSpec** /* free result */g_object_class_list_properties (GObjectClass *class, guint *n_properties_p){ GParamSpec **pspecs; guint n; g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); pspecs = g_param_spec_pool_list (pspec_pool, G_OBJECT_CLASS_TYPE (class), &n); if (n_properties_p) *n_properties_p = n; return pspecs;}static voidg_object_init (GObject *object){ object->ref_count = 1; g_datalist_init (&object->qdata); /* freeze object's notification queue, g_object_newv() preserves pairedness */ g_object_notify_queue_freeze (object, &property_notify_context); #ifdef G_ENABLE_DEBUG IF_DEBUG (OBJECTS) { G_LOCK (debug_objects); debug_objects_count++; g_hash_table_insert (debug_objects_ht, object, object); G_UNLOCK (debug_objects); }#endif /* G_ENABLE_DEBUG */}static voidg_object_do_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec){ switch (property_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; }}static voidg_object_do_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec){ switch (property_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; }}static voidg_object_real_dispose (GObject *object){ guint ref_count; g_signal_handlers_destroy (object); g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); /* yes, temporarily altering the ref_count is hackish, but that * enforces people not jerking around with weak_ref notifiers */ ref_count = object->ref_count; object->ref_count = 0; g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); object->ref_count = ref_count;}static voidg_object_finalize (GObject *object){ g_datalist_clear (&object->qdata); #ifdef G_ENABLE_DEBUG IF_DEBUG (OBJECTS) { G_LOCK (debug_objects); g_assert (g_hash_table_lookup (debug_objects_ht, object) == object); g_hash_table_remove (debug_objects_ht, object); debug_objects_count--; G_UNLOCK (debug_objects); }#endif /* G_ENABLE_DEBUG */}static voidg_object_last_unref (GObject *object){ g_return_if_fail (object->ref_count > 0); if (object->ref_count == 1) /* may have been re-referenced meanwhile */ G_OBJECT_GET_CLASS (object)->dispose (object); #ifdef G_ENABLE_DEBUG if (g_trap_object_ref == object) G_BREAKPOINT ();#endif /* G_ENABLE_DEBUG */ object->ref_count -= 1; if (object->ref_count == 0) /* may have been re-referenced meanwhile */ { g_signal_handlers_destroy (object); g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); G_OBJECT_GET_CLASS (object)->finalize (object);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -