📄 gtktypeutils.c
字号:
/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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. *//* * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */#include <string.h>#include "gtktypeutils.h"#define TYPE_NODES_BLOCK_SIZE (35) /* needs to be > GTK_TYPE_FUNDAMENTAL_MAX */typedef struct _GtkTypeNode GtkTypeNode;struct _GtkTypeNode{ GtkType type; GtkTypeInfo type_info; guint n_supers : 24; guint chunk_alloc_locked : 1; GtkType *supers; GtkType parent_type; gpointer klass; GList *children_types; GMemChunk *mem_chunk;};#define LOOKUP_TYPE_NODE(node_var, type) { \ GtkTypeNode *__node = NULL; \ GtkType sqn = GTK_TYPE_SEQNO (type); \ if (sqn > 0) \ { \ sqn--; \ if (sqn < GTK_TYPE_FUNDAMENTAL_MAX) \ { \ if (sqn < n_ftype_nodes) \ __node = type_nodes + sqn; \ } \ else if (sqn < n_type_nodes) \ __node = type_nodes + sqn; \ } \ node_var = __node; \}static void gtk_type_class_init (GtkType node_type);static guint gtk_type_name_hash (const char *key);static gint gtk_type_name_compare (const char *a, const char *b);static void gtk_type_init_builtin_types (void);static GtkTypeNode *type_nodes = NULL;static guint n_type_nodes = 0;static guint n_ftype_nodes = 0;static GHashTable *type_name_2_type_ht = NULL;static GtkTypeNode*gtk_type_node_next_and_invalidate (GtkType parent_type){ static guint n_free_type_nodes = 0; GtkTypeNode *node; /* don't keep *any* GtkTypeNode pointers across invokation of this function!!! */ if (n_free_type_nodes == 0) { guint i; guint size; /* nearest pow */ size = n_type_nodes + TYPE_NODES_BLOCK_SIZE; size *= sizeof (GtkTypeNode); i = 1; while (i < size) i <<= 1; size = i; type_nodes = g_realloc (type_nodes, size); n_free_type_nodes = size / sizeof (GtkTypeNode) - n_type_nodes; memset (type_nodes + n_type_nodes, 0, n_free_type_nodes * sizeof (GtkTypeNode)); if (!n_type_nodes) { n_type_nodes = GTK_TYPE_FUNDAMENTAL_MAX; n_free_type_nodes -= GTK_TYPE_FUNDAMENTAL_MAX; } } if (!parent_type) { g_assert (n_ftype_nodes < GTK_TYPE_FUNDAMENTAL_MAX); /* paranoid */ node = type_nodes + n_ftype_nodes; n_ftype_nodes++; node->type = n_ftype_nodes; } else { node = type_nodes + n_type_nodes; n_type_nodes++; n_free_type_nodes--; node->type = GTK_TYPE_MAKE (parent_type, n_type_nodes); } return node;}voidgtk_type_init (void){ if (n_type_nodes == 0) { g_assert (sizeof (GtkType) >= 4); g_assert (TYPE_NODES_BLOCK_SIZE > GTK_TYPE_FUNDAMENTAL_MAX); type_name_2_type_ht = g_hash_table_new ((GHashFunc) gtk_type_name_hash, (GCompareFunc) gtk_type_name_compare); gtk_type_init_builtin_types (); }}voidgtk_type_set_chunk_alloc (GtkType type, guint n_chunks){ GtkTypeNode *node; LOOKUP_TYPE_NODE (node, type); g_return_if_fail (node != NULL); g_return_if_fail (node->chunk_alloc_locked == FALSE); if (node->mem_chunk) { g_mem_chunk_destroy (node->mem_chunk); node->mem_chunk = NULL; } if (n_chunks) node->mem_chunk = g_mem_chunk_new (node->type_info.type_name, node->type_info.object_size, node->type_info.object_size * n_chunks, G_ALLOC_AND_FREE);}static GtkTypegtk_type_create (GtkType parent_type, gchar *type_name, const GtkTypeInfo *type_info){ GtkTypeNode *new_node; GtkTypeNode *parent; guint i; if (g_hash_table_lookup (type_name_2_type_ht, type_name)) { g_warning ("gtk_type_create(): type `%s' already exists.", type_name); return 0; } if (parent_type) { GtkTypeNode *tmp_node; LOOKUP_TYPE_NODE (tmp_node, parent_type); if (!tmp_node) { g_warning ("gtk_type_create(): unknown parent type `%u'.", parent_type); return 0; } } /* relookup pointers afterwards. */ new_node = gtk_type_node_next_and_invalidate (parent_type); if (parent_type) { g_assert (GTK_TYPE_SEQNO (new_node->type) > GTK_TYPE_FUNDAMENTAL_MAX); LOOKUP_TYPE_NODE (parent, parent_type); } else { g_assert (new_node->type <= GTK_TYPE_FUNDAMENTAL_MAX); parent = NULL; } new_node->type_info = *type_info; new_node->type_info.type_name = type_name; /* new_node->type_info.reserved_1 = NULL; */ new_node->type_info.reserved_2 = NULL; new_node->n_supers = parent ? parent->n_supers + 1 : 0; new_node->chunk_alloc_locked = FALSE; new_node->supers = g_new0 (GtkType, new_node->n_supers + 1); new_node->parent_type = parent_type; new_node->klass = NULL; new_node->children_types = NULL; new_node->mem_chunk = NULL; if (parent) parent->children_types = g_list_append (parent->children_types, GUINT_TO_POINTER (new_node->type)); parent = new_node; for (i = 0; i < new_node->n_supers + 1; i++) { new_node->supers[i] = parent->type; LOOKUP_TYPE_NODE (parent, parent->parent_type); } g_hash_table_insert (type_name_2_type_ht, new_node->type_info.type_name, GUINT_TO_POINTER (new_node->type)); return new_node->type;}GtkTypegtk_type_unique (GtkType parent_type, const GtkTypeInfo *type_info){ GtkType new_type; gchar *type_name; g_return_val_if_fail (type_info != NULL, 0); g_return_val_if_fail (type_info->type_name != NULL, 0); if (!parent_type && n_ftype_nodes >= GTK_TYPE_FUNDAMENTAL_MAX) { g_warning ("gtk_type_unique(): maximum amount of fundamental types reached, " "try increasing GTK_TYPE_FUNDAMENTAL_MAX"); return 0; } type_name = g_strdup (type_info->type_name); /* relookup pointers afterwards. */ new_type = gtk_type_create (parent_type, type_name, type_info); if (!new_type) g_free (type_name); return new_type;}gchar*gtk_type_name (GtkType type){ GtkTypeNode *node; LOOKUP_TYPE_NODE (node, type); if (node) return node->type_info.type_name; return NULL;}GtkTypegtk_type_from_name (const gchar *name){ if (type_name_2_type_ht) { GtkType type; type = GPOINTER_TO_UINT (g_hash_table_lookup (type_name_2_type_ht, (gpointer) name)); return type; } return 0;}GtkTypegtk_type_parent (GtkType type){ GtkTypeNode *node; LOOKUP_TYPE_NODE (node, type); if (node) return node->parent_type; return 0;}gpointergtk_type_parent_class (GtkType type){ GtkTypeNode *node; LOOKUP_TYPE_NODE (node, type); g_return_val_if_fail (node != NULL, NULL); if (node) { LOOKUP_TYPE_NODE (node, node->parent_type); if (node) { if (!node->klass) { type = node->type; gtk_type_class_init (type); LOOKUP_TYPE_NODE (node, type); } return node->klass; } } return NULL;}gpointergtk_type_class (GtkType type){ GtkTypeNode *node; LOOKUP_TYPE_NODE (node, type); g_return_val_if_fail (node != NULL, NULL); if (!node->klass) { type = node->type; gtk_type_class_init (type); LOOKUP_TYPE_NODE (node, type); } return node->klass;}gpointergtk_type_new (GtkType type){ GtkTypeNode *node; GtkTypeObject *tobject; gpointer klass; LOOKUP_TYPE_NODE (node, type); g_return_val_if_fail (node != NULL, NULL); klass = node->klass; if (!klass) { klass = gtk_type_class (type); LOOKUP_TYPE_NODE (node, type); } node->chunk_alloc_locked = TRUE; if (node->mem_chunk) tobject = g_mem_chunk_alloc0 (node->mem_chunk); else tobject = g_malloc0 (node->type_info.object_size); /* we need to call the base classes' object_init_func for derived * objects with the object's ->klass field still pointing to the * corresponding base class, otherwise overridden class functions * could get called with partly-initialized objects. the real object * class is passed as second argment to the initializers. */ if (node->n_supers) { guint i; GtkType *supers; GtkTypeNode *pnode; supers = node->supers; for (i = node->n_supers; i > 0; i--) { LOOKUP_TYPE_NODE (pnode, supers[i]); if (pnode->type_info.object_init_func) { tobject->klass = pnode->klass; pnode->type_info.object_init_func (tobject, klass); } } LOOKUP_TYPE_NODE (node, type); } tobject->klass = klass; if (node->type_info.object_init_func) { node->type_info.object_init_func (tobject, klass); tobject->klass = klass; } return tobject;}voidgtk_type_free (GtkType type, gpointer mem){ GtkTypeNode *node; g_return_if_fail (mem != NULL); LOOKUP_TYPE_NODE (node, type); g_return_if_fail (node != NULL); if (node->mem_chunk) g_mem_chunk_free (node->mem_chunk, mem); else g_free (mem);}GList*gtk_type_children_types (GtkType type){ GtkTypeNode *node; LOOKUP_TYPE_NODE (node, type); if (node) return node->children_types; return NULL;}voidgtk_type_describe_heritage (GtkType type){ GtkTypeNode *node; gchar *is_a = ""; LOOKUP_TYPE_NODE (node, type); while (node) { if (node->type_info.type_name) g_message ("%s%s", is_a, node->type_info.type_name); else g_message ("%s<unnamed type>", is_a); is_a = "is a "; LOOKUP_TYPE_NODE (node, node->parent_type); }}voidgtk_type_describe_tree (GtkType type, gboolean show_size){ GtkTypeNode *node; LOOKUP_TYPE_NODE (node, type); if (node) { static gint indent = 0; GList *list; guint old_indent; guint i; GString *gstring; gstring = g_string_new (""); for (i = 0; i < indent; i++) g_string_append_c (gstring, ' '); if (node->type_info.type_name) g_string_append (gstring, node->type_info.type_name); else g_string_append (gstring, "<unnamed type>"); if (show_size) g_string_sprintfa (gstring, " (%d bytes)", node->type_info.object_size); g_message ("%s", gstring->str); g_string_free (gstring, TRUE); old_indent = indent; indent += 4; for (list = node->children_types; list; list = list->next) gtk_type_describe_tree (GPOINTER_TO_UINT (list->data), show_size); indent = old_indent; }}gbooleangtk_type_is_a (GtkType type, GtkType is_a_type){ if (type == is_a_type) return TRUE; else { GtkTypeNode *node; LOOKUP_TYPE_NODE (node, type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -