diff --git a/include/QF/gib.h b/include/QF/gib.h index 107885981..0804a1bb0 100644 --- a/include/QF/gib.h +++ b/include/QF/gib.h @@ -62,6 +62,7 @@ typedef struct gib_object_s { unsigned long int handle, refs; hashtab_t *signals; llist_t *slots; + const char *handstr; } gib_object_t; typedef struct gib_message_s { @@ -93,6 +94,7 @@ typedef struct gib_class_s { unsigned int depth; struct gib_object_s *classobj; struct gib_class_s *parent; + llist_t *children; } gib_class_t; typedef struct gib_methodtab_s { @@ -109,9 +111,6 @@ typedef struct gib_classdesc_s { struct gib_methodtab_s *methods, *class_methods; } gib_classdesc_t; -#define GIB_Reply(obj,mesg,argc,argv) if ((mesg).reply) { \ - ((mesg).reply(argc,argv,(mesg).replydata)); \ - GIB_Object_Decref ((obj));} #define GIB_ForwardToSuper(mesg,obj,method) ((method)->parent->func ((obj), \ (method)->parent, \ (obj)->data[(method)->parent->class->depth], \ @@ -126,6 +125,8 @@ int GIB_Send (gib_object_t *obj, gib_object_t *sender, int argc, const char **ar int GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, gib_object_t *sender, int argc, const char **argv, gib_reply_handler reply, void *replydata); +void GIB_Reply (gib_object_t *obj, gib_message_t mesg, int argc, const char + **argv); gib_object_t *GIB_Object_Get (const char *id); void GIB_Object_Signal_Slot_Pair (gib_object_t *sender, const char *signal, gib_object_t *receiver, const char *slot); diff --git a/libs/gib/gib_classes.c b/libs/gib/gib_classes.c index 5b318da59..a03de1e90 100644 --- a/libs/gib/gib_classes.c +++ b/libs/gib/gib_classes.c @@ -64,13 +64,11 @@ static int Object_Retain_f (gib_object_t *obj, gib_method_t *method, void *data, gib_object_t *sender, gib_message_t mesg) { - const char *r; baseobj_t *base = data; base->ref++; GIB_Object_Incref (obj); - r = va ("%lu", obj->handle); - GIB_Reply (obj, mesg, 1, &r); + GIB_Reply (obj, mesg, 1, &obj->handstr); return 0; } @@ -91,10 +89,7 @@ static int Object_Init_f (gib_object_t *obj, gib_method_t *method, void *data, gib_object_t *sender, gib_message_t mesg) { - const char *r; - - r = va ("%lu", obj->handle); - GIB_Reply (obj, mesg, 1, &r); + GIB_Reply (obj, mesg, 1, &obj->handstr); return 0; } @@ -106,6 +101,37 @@ Object_Class_f (gib_object_t *obj, gib_method_t *method, void *data, return 0; } +static int +Object_SuperClass_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_object_t *sender, gib_message_t mesg) +{ + if (obj->class->parent) + GIB_Reply (obj, mesg, 1, &obj->class->parent->name); + else + GIB_Reply (obj, mesg, 0, NULL); + return 0; +} + +static int +Object_IsKindOf_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_object_t *sender, gib_message_t mesg) +{ + gib_class_t *c; + static const char *one = "1"; + static const char *zero = "0"; + + if (mesg.argc < 2) + return -1; + + for (c = obj->class; c; c = c->parent) + if (!strcmp (mesg.argv[1], c->name)) { + GIB_Reply (obj, mesg, 1, &one); + return 0; + } + GIB_Reply (obj, mesg, 1, &zero); + return 0; +} + static int Object_Dispose_f (gib_object_t *obj, gib_method_t *method, void *data, gib_object_t *sender, gib_message_t mesg) @@ -157,6 +183,31 @@ Object_Class_New_f (gib_object_t *obj, gib_method_t *method, void *data, mesg.argv[0] = old; return 0; } + +static int +Object_Class_Children_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_object_t *sender, gib_message_t mesg) +{ + const char **reply; + unsigned int size; + unsigned int i = 0; + + static qboolean + iterator (gib_class_t *class, void *unused) + { + reply[i++] = class->name; + return false; + } + + size = llist_size (obj->class->children); + if (size) { + reply = malloc (sizeof (char *) * size); + llist_iterate (obj->class->children, LLIST_ICAST (iterator)); + GIB_Reply (obj, mesg, size, reply); + } else + GIB_Reply (obj, mesg, 0, NULL); + return 0; +} static void * Object_Construct (gib_object_t *obj) @@ -180,6 +231,8 @@ gib_methodtab_t Object_methods[] = { {"release", Object_Release_f, NULL}, {"init", Object_Init_f, NULL}, {"class", Object_Class_f, NULL}, + {"superClass", Object_SuperClass_f, NULL}, + {"isKindOf", Object_IsKindOf_f, NULL}, {"dispose", Object_Dispose_f, NULL}, {"signalConnect", Object_SignalConnect_f, NULL}, {"signalDisconnect", Object_SignalDisconnect_f, NULL}, @@ -187,6 +240,8 @@ gib_methodtab_t Object_methods[] = { }; gib_methodtab_t Object_class_methods[] = { + {"parent", Object_SuperClass_f, NULL}, + {"children", Object_Class_Children_f, NULL}, {"new", Object_Class_New_f, NULL}, {"signalConnect", Object_SignalConnect_f, NULL}, {"signalDisconnect", Object_SignalDisconnect_f, NULL}, @@ -296,6 +351,162 @@ gib_classdesc_t Thread_class = { Thread_methods, Thread_class_methods }; +/* + Object hash class + + Stores references to objects in a Hash +*/ + +typedef struct ObjRef_s { + const char *key; + gib_object_t *obj; +} ObjRef_t; + +typedef struct ObjectHash_s { + hashtab_t *objects; +} ObjectHash_t; + +static const char * +ObjRef_Get_Key (void *ele, void *ptr) +{ + return ((ObjRef_t *) ele)->key; +} + +static void +ObjRef_Free (void *ele, void *ptr) +{ + ObjRef_t *ref = ele; + free ((void *)ref->key); + GIB_Object_Decref (ref->obj); + free (ref); +} + +static void * +ObjectHash_Construct (gib_object_t *obj) +{ + ObjectHash_t *data = malloc (sizeof (ObjectHash_t)); + + data->objects = Hash_NewTable (1024, ObjRef_Get_Key, ObjRef_Free, + NULL); + + return data; +} + +static void +ObjectHash_Destruct (void *data) +{ + ObjectHash_t *objh = data; + + Hash_DelTable (objh->objects); + free (objh); +} + +static int +ObjectHash_Insert_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_object_t *sender, gib_message_t mesg) +{ + ObjectHash_t *objh = data; + gib_object_t *ins; + ObjRef_t *new; + int i; + + if (mesg.argc < 3) + return -1; + + for (i = 2; i < mesg.argc; i++) { + if ((ins = GIB_Object_Get (mesg.argv[i]))) { + new = malloc (sizeof (ObjRef_t)); + new->key = strdup (mesg.argv[1]); + new->obj = ins; + GIB_Object_Incref (ins); + Hash_Add (objh->objects, new); + } else + return -1; + } + + GIB_Reply (obj, mesg, 0, NULL); + return 0; +} + +static int +ObjectHash_Get_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_object_t *sender, gib_message_t mesg) +{ + ObjectHash_t *objh = data; + ObjRef_t **refs, **r; + const char **reply; + int i, len; + + if (mesg.argc < 2) + return -1; + + if ((refs = (ObjRef_t **) Hash_FindList (objh->objects, + mesg.argv[1]))) { + for (r = refs, len = 0; *r; r++, len++); + reply = malloc (sizeof (char **) * len); + for (r = refs, i = 0; *r; r++, i++) + reply[i] = (*r)->obj->handstr; + GIB_Reply (obj, mesg, len, reply); + free (reply); + } else + GIB_Reply (obj, mesg, 0, NULL); + return 0; +} + +static int +ObjectHash_Remove_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_object_t *sender, gib_message_t mesg) +{ + ObjectHash_t *objh = data; + ObjRef_t **refs, **r; + int i; + + if (mesg.argc < 2) + return -1; + + if ((refs = (ObjRef_t **) Hash_FindList (objh->objects, + mesg.argv[1]))) { + if (mesg.argc == 2) + for (r = refs; *r; r++) { + Hash_DelElement (objh->objects, *r); + Hash_Free (objh->objects, *r); + } + else + for (r = refs; *r; r++) + for (i = 2; i < mesg.argc; i++) + if (!strcmp (mesg.argv[i], + (*r)->obj->handstr)) + { + Hash_DelElement + (objh->objects, + *r); + Hash_Free + (objh->objects, + *r); + } + } + GIB_Reply (obj, mesg, 0, NULL); + return 0; +} + +gib_methodtab_t ObjectHash_methods[] = { + {"insert", ObjectHash_Insert_f, NULL}, + {"get", ObjectHash_Get_f, NULL}, + {"remove", ObjectHash_Remove_f, NULL}, + {NULL, NULL, NULL} +}; + +gib_methodtab_t ObjectHash_class_methods[] = { + {NULL, NULL, NULL} +}; + +gib_classdesc_t ObjectHash_class = { + "ObjectHash", "Object", + ObjectHash_Construct, NULL, + ObjectHash_Destruct, + ObjectHash_methods, ObjectHash_class_methods +}; + /* Scripted object class factory @@ -472,4 +683,5 @@ GIB_Classes_Init (void) { GIB_Class_Create (&Object_class); GIB_Class_Create (&Thread_class); + GIB_Class_Create (&ObjectHash_class); } diff --git a/libs/gib/gib_object.c b/libs/gib/gib_object.c index 4aa303950..a4d38f038 100644 --- a/libs/gib/gib_object.c +++ b/libs/gib/gib_object.c @@ -161,6 +161,7 @@ GIB_Class_Create (gib_classdesc_t *desc) if (desc->parentname && (parent = Hash_Find (gib_classes, desc->parentname))) { class->parent = parent; class->depth = parent->depth + 1; + llist_append (parent->children, class); } else class->depth = 0; @@ -173,6 +174,7 @@ GIB_Class_Create (gib_classdesc_t *desc) parent->methods : NULL, desc->methods); class->class_methods = GIB_Method_Build_Hash (class, parent ? parent->class_methods : NULL, desc->class_methods); + class->children = llist_new (NULL, NULL, NULL); Hash_Add (gib_classes, class); @@ -205,6 +207,7 @@ GIB_Object_Create (const char *classname, qboolean classobj) obj->data = malloc (sizeof (void *) * (class->depth+1)); obj->methods = classobj ? class->class_methods : class->methods; obj->handle = classobj ? 0 : GIB_Handle_New (obj); + obj->handstr = strdup (va ("%lu", obj->handle)); obj->refs = 1; obj->signals = Hash_NewTable (128, GIB_Signal_Get_Key, GIB_Signal_Free, NULL); @@ -235,6 +238,7 @@ GIB_Object_Finish_Destroy (int argc, const char **argv, void *data) temp->destruct (obj->data[i]); free (obj->data); GIB_Handle_Free (obj->handle); + free ((void *) obj->handstr); Hash_DelTable (obj->signals); llist_delete (obj->slots); free (obj); @@ -308,6 +312,14 @@ GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, gib_object_t sender, message); } +void +GIB_Reply (gib_object_t *obj, gib_message_t mesg, int argc, const char + **argv) +{ + mesg.reply (argc, argv, mesg.replydata); + GIB_Object_Decref (obj); +} + gib_object_t * GIB_Object_Get (const char *id) {