2007-12-30 17:41:49 +01:00
|
|
|
|
/***************************************************************************
|
|
|
|
|
|
|
|
|
|
Object.c
|
|
|
|
|
|
|
|
|
|
Object management routines
|
|
|
|
|
|
|
|
|
|
(c) 2000-2007 Benoit Minisini <gambas@users.sourceforge.net>
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 1, or (at your option)
|
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
#define __OBJECT_C
|
|
|
|
|
|
|
|
|
|
#include "gb_common.h"
|
|
|
|
|
#include "gb_alloc.h"
|
|
|
|
|
#include "gb_list.h"
|
|
|
|
|
#include "gbx_class.h"
|
|
|
|
|
#include "gbx_event.h"
|
|
|
|
|
#include "gbx_exec.h"
|
|
|
|
|
#include "gbx_compare.h"
|
|
|
|
|
#include "gbx_c_gambas.h"
|
|
|
|
|
#include "gbx_object.h"
|
|
|
|
|
|
|
|
|
|
static OBJECT *EventObject = NULL;
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_new(void **ptr, CLASS *class, const char *name, OBJECT *parent)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
OBJECT_alloc(ptr, class, class->size);
|
|
|
|
|
|
|
|
|
|
//#if DEBUG_EVENT
|
|
|
|
|
//printf("OBJECT_new: %s %p %d\n", class->name, *ptr, class->off_event);
|
|
|
|
|
//#endif
|
|
|
|
|
|
|
|
|
|
OBJECT_attach(*ptr, parent, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_alloc(void **ptr, CLASS *class, size_t size)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
OBJECT *object;
|
|
|
|
|
|
|
|
|
|
if (size < sizeof(OBJECT))
|
2008-01-17 22:39:26 +01:00
|
|
|
|
size = sizeof(OBJECT);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
ALLOC_ZERO(&object, size, "OBJECT_alloc");
|
|
|
|
|
|
|
|
|
|
object->class = class;
|
|
|
|
|
object->ref = 1;
|
|
|
|
|
|
|
|
|
|
class->count++;
|
|
|
|
|
|
|
|
|
|
*ptr = object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
static void dump_attach(char *title)
|
|
|
|
|
{
|
|
|
|
|
void *ob;
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, ">>>> %s: ", title);
|
|
|
|
|
for (ob = EventObject; ob; ob = OBJECT_event(ob)->next)
|
|
|
|
|
fprintf(stderr, "%p -> ", ob);
|
|
|
|
|
fprintf(stderr, "(nil)\n");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_detach(OBJECT *ob)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CLASS *class = OBJECT_class(ob);
|
|
|
|
|
OBJECT *parent;
|
|
|
|
|
OBJECT_EVENT *ev;
|
|
|
|
|
bool lock;
|
|
|
|
|
|
|
|
|
|
ev = (OBJECT_EVENT *)((char *)ob + class->off_event);
|
|
|
|
|
|
|
|
|
|
//if (!ev->parent)
|
|
|
|
|
// return;
|
|
|
|
|
|
|
|
|
|
if (ev->prev)
|
|
|
|
|
OBJECT_event(ev->prev)->next = ev->next;
|
|
|
|
|
|
|
|
|
|
if (ev->next)
|
|
|
|
|
OBJECT_event(ev->next)->prev = ev->prev;
|
|
|
|
|
|
|
|
|
|
if (ob == EventObject)
|
|
|
|
|
EventObject = ev->next;
|
|
|
|
|
|
|
|
|
|
ev->prev = NULL;
|
|
|
|
|
ev->next = NULL;
|
|
|
|
|
|
|
|
|
|
//dump_attach("OBJECT_detach");
|
|
|
|
|
|
2008-02-14 12:59:36 +01:00
|
|
|
|
// Do not free the observers there anymore
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
/* Avoids an infinite recursion, if freeing the parent implies freeing the object */
|
|
|
|
|
parent = OBJECT_parent(ob);
|
|
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
|
{
|
|
|
|
|
lock = OBJECT_is_locked(ob);
|
|
|
|
|
ev->parent = NULL;
|
|
|
|
|
OBJECT_lock(ob, lock);
|
|
|
|
|
#if DEBUG_EVENT || DEBUG_REF
|
|
|
|
|
fprintf(stderr, "OBJECT_detach : Detach (%s %p) from (%s %p)\n",
|
|
|
|
|
ob->class->name, ob, parent->class->name, parent);
|
|
|
|
|
#endif
|
2008-08-14 21:42:27 +02:00
|
|
|
|
OBJECT_UNREF(parent, "OBJECT_detach");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-14 12:59:36 +01:00
|
|
|
|
static void remove_observers(OBJECT *ob)
|
|
|
|
|
{
|
|
|
|
|
CLASS *class = OBJECT_class(ob);
|
|
|
|
|
OBJECT_EVENT *ev;
|
|
|
|
|
COBSERVER *obs, *next;
|
|
|
|
|
|
|
|
|
|
ev = (OBJECT_EVENT *)((char *)ob + class->off_event);
|
|
|
|
|
obs = ev->observer;
|
|
|
|
|
|
|
|
|
|
while (obs)
|
|
|
|
|
{
|
|
|
|
|
next = obs->list.next;
|
|
|
|
|
#if DEBUG_EVENT
|
|
|
|
|
fprintf(stderr, "Remove observer %p\n", obs);
|
|
|
|
|
#endif
|
2008-08-14 21:42:27 +02:00
|
|
|
|
OBJECT_UNREF(obs, "remove_observers");
|
2008-02-14 12:59:36 +01:00
|
|
|
|
obs = next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ev->observer = NULL;
|
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_attach(OBJECT *ob, OBJECT *parent, const char *name)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CLASS *class = OBJECT_class(ob);
|
|
|
|
|
OBJECT_EVENT *ev;
|
|
|
|
|
bool lock;
|
|
|
|
|
|
|
|
|
|
if (EVENT_Name != name)
|
|
|
|
|
{
|
2008-02-21 14:14:16 +01:00
|
|
|
|
STRING_unref(&EVENT_Name);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
if (name)
|
|
|
|
|
STRING_new(&EVENT_Name, name, 0);
|
2008-02-21 14:14:16 +01:00
|
|
|
|
else
|
|
|
|
|
EVENT_Name = NULL;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
lock = OBJECT_is_locked(ob);
|
|
|
|
|
|
|
|
|
|
OBJECT_detach(ob);
|
|
|
|
|
|
|
|
|
|
ev = (OBJECT_EVENT *)((char *)ob + class->off_event);
|
|
|
|
|
|
|
|
|
|
ev->parent = parent;
|
|
|
|
|
|
|
|
|
|
OBJECT_lock(ob, lock);
|
|
|
|
|
|
|
|
|
|
#if DEBUG_EVENT || DEBUG_REF
|
|
|
|
|
fprintf(stderr, "OBJECT_attach : Attach (%s %p) to (%s %p) as %s\n",
|
|
|
|
|
ob->class->name, ob, parent->class->name, parent, name);
|
|
|
|
|
#endif
|
|
|
|
|
OBJECT_REF(parent, "OBJECT_attach");
|
|
|
|
|
|
|
|
|
|
EVENT_search(class, ev->event, name, parent);
|
|
|
|
|
|
|
|
|
|
ev->next = EventObject;
|
|
|
|
|
ev->prev = NULL;
|
|
|
|
|
|
|
|
|
|
if (EventObject)
|
|
|
|
|
OBJECT_event(EventObject)->prev = ob;
|
|
|
|
|
|
|
|
|
|
EventObject = ob;
|
|
|
|
|
|
|
|
|
|
//dump_attach("OBJECT_attach");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_free(CLASS *class, OBJECT *ob)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
/* Il faut emp<6D>her EXEC_leave() de relib<69>er l'objet */
|
|
|
|
|
/*((OBJECT *)free_ptr)->ref = 1;*/
|
|
|
|
|
|
|
|
|
|
/*OBJECT_REF(ob, "OBJECT_free");*/
|
|
|
|
|
|
|
|
|
|
/* Ex<45>ution de la m<>hode _free pour toutes les classes parentes
|
|
|
|
|
puis pour la classe de l'objet */
|
|
|
|
|
|
|
|
|
|
/*if (CLASS_is_native(class))
|
|
|
|
|
EXEC_special_inheritance(SPEC_FREE, class, ob, 0, TRUE);*/
|
|
|
|
|
|
|
|
|
|
OBJECT_detach(ob);
|
2008-02-14 12:59:36 +01:00
|
|
|
|
remove_observers(ob);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
|
|
class->count--;
|
|
|
|
|
|
|
|
|
|
#if DEBUG_REF
|
|
|
|
|
ob->class = (CLASS *)0x23232323;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
FREE(&ob, "OBJECT_free");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
bool OBJECT_comp_value(VALUE *ob1, VALUE *ob2)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
if (ob1->type == T_NULL && ob2->type == T_NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
else if (ob1->type == T_NULL)
|
|
|
|
|
return ob2->_object.object != NULL;
|
|
|
|
|
else if (ob2->type == T_NULL)
|
|
|
|
|
return ob1->_object.object != NULL;
|
|
|
|
|
else
|
|
|
|
|
return COMPARE_object(&ob1->_object.object, &ob2->_object.object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void release(CLASS *class, OBJECT *ob)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
CLASS_VAR *var;
|
|
|
|
|
int nelt;
|
|
|
|
|
char *data;
|
|
|
|
|
|
|
|
|
|
if (class->parent != NULL && ob)
|
|
|
|
|
release(class->parent, ob);
|
|
|
|
|
|
|
|
|
|
if (CLASS_is_native(class))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (ob == NULL)
|
|
|
|
|
{
|
|
|
|
|
var = class->load->stat;
|
|
|
|
|
nelt = class->load->n_stat;
|
|
|
|
|
data = class->stat;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var = class->load->dyn;
|
|
|
|
|
nelt = class->load->n_dyn;
|
|
|
|
|
data = (char *)ob;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < nelt; i++)
|
|
|
|
|
{
|
|
|
|
|
#if TRACE_MEMORY
|
|
|
|
|
if (var->type.id == T_STRING || var->type.id == T_OBJECT)
|
|
|
|
|
{
|
|
|
|
|
printf("release: %s %p [%d] trying %p\n", class->name, ob, i, (*(void **)&data[var->pos]));
|
|
|
|
|
fflush(NULL);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (var->type.id == T_STRING)
|
|
|
|
|
STRING_unref((char **)&data[var->pos]);
|
|
|
|
|
else if (var->type.id == T_OBJECT)
|
|
|
|
|
{
|
2008-08-14 21:42:27 +02:00
|
|
|
|
OBJECT_UNREF(*((void **)&data[var->pos]), "release");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
else if (var->type.id == T_VARIANT)
|
|
|
|
|
VARIANT_free((VARIANT *)&data[var->pos]);
|
|
|
|
|
else if (var->type.id == T_ARRAY)
|
|
|
|
|
ARRAY_free_data((void *)&data[var->pos], (ARRAY_DESC *)class->load->array[var->type.value]);
|
|
|
|
|
|
|
|
|
|
var++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_release(CLASS *class, OBJECT *ob)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
#if TRACE_MEMORY
|
|
|
|
|
printf("> OBJECT_release %s %p\n", class->name, ob);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
release(class, ob);
|
|
|
|
|
|
|
|
|
|
if (ob)
|
|
|
|
|
OBJECT_free(class, ob);
|
|
|
|
|
|
|
|
|
|
#if TRACE_MEMORY
|
|
|
|
|
printf("< OBJECT_release %s %p\n", class->name, ob);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_exit(void)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
|
fprintf(stderr, "------------ OBJECT_exit - BEGIN---------\n");
|
|
|
|
|
#endif
|
|
|
|
|
while (EventObject)
|
|
|
|
|
OBJECT_detach(EventObject);
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
|
fprintf(stderr, "------------ OBJECT_exit - END ----------\n");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_create(void **object, CLASS *class, const char *name, void *parent, int nparam)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
void *ob;
|
|
|
|
|
|
|
|
|
|
if (class->no_create)
|
|
|
|
|
THROW(E_CSTATIC, class->name);
|
|
|
|
|
|
|
|
|
|
TRY
|
|
|
|
|
{
|
|
|
|
|
OBJECT_new(&ob, class, name, parent);
|
|
|
|
|
*object = ob;
|
|
|
|
|
OBJECT_lock(ob, TRUE);
|
|
|
|
|
EXEC_special_inheritance(SPEC_NEW, class, ob, nparam, TRUE);
|
|
|
|
|
OBJECT_lock(ob, FALSE);
|
2008-08-14 21:42:27 +02:00
|
|
|
|
OBJECT_UNREF_KEEP(ob, "OBJECT_create");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
CATCH
|
|
|
|
|
{
|
|
|
|
|
*object = NULL;
|
2008-08-14 21:42:27 +02:00
|
|
|
|
OBJECT_UNREF_KEEP(ob, "OBJECT_create");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
PROPAGATE();
|
|
|
|
|
}
|
|
|
|
|
END_TRY
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* FIXME: The _new are methods called differently from EXEC_special_inheritance */
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_create_native(void **object, CLASS *class, VALUE *param)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CLASS_DESC *desc;
|
|
|
|
|
short index;
|
|
|
|
|
|
|
|
|
|
OBJECT_new(object, class, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
for(;;)
|
|
|
|
|
{
|
|
|
|
|
index = class->special[SPEC_NEW];
|
|
|
|
|
if (index != NO_SYMBOL)
|
|
|
|
|
{
|
|
|
|
|
desc = CLASS_get_desc(class, index);
|
|
|
|
|
EXEC_call_native(desc->method.exec, *object, desc->method.type, param);
|
|
|
|
|
}
|
|
|
|
|
class = class->parent;
|
|
|
|
|
if (!class)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-14 21:42:27 +02:00
|
|
|
|
OBJECT_UNREF_KEEP(*object, "OBJECT_create");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
void OBJECT_lock(OBJECT *object, bool block)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
CLASS *class;
|
|
|
|
|
|
|
|
|
|
if (!object)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
class = object->class;
|
|
|
|
|
if (class->n_event == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// fprintf(stderr, "OBJECT_lock: (%s %p) %s\n", class->name, object, block ? "lock" : "unlock");
|
|
|
|
|
|
|
|
|
|
if (block)
|
2008-01-17 22:39:26 +01:00
|
|
|
|
OBJECT_event(object)->parent = (OBJECT *)((intptr_t)OBJECT_event(object)->parent | 1);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
else
|
2008-01-17 22:39:26 +01:00
|
|
|
|
OBJECT_event(object)->parent = (OBJECT *)((intptr_t)OBJECT_event(object)->parent & ~1);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
bool OBJECT_is_locked(OBJECT *object)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
if (!OBJECT_has_events(object))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
return (((intptr_t)OBJECT_event(object)->parent & 1) != 0);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
OBJECT *OBJECT_parent(void *object)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
//if (!OBJECT_has_events(object))
|
|
|
|
|
// return NULL;
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
return ((OBJECT *)((intptr_t)OBJECT_event(object)->parent & ~1));
|
2007-12-30 17:41:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
|
OBJECT *OBJECT_active_parent(void *object)
|
2007-12-30 17:41:49 +01:00
|
|
|
|
{
|
|
|
|
|
OBJECT *parent = OBJECT_parent(object);
|
|
|
|
|
|
|
|
|
|
if (!parent || OBJECT_is_locked((OBJECT *)object) || OBJECT_is_locked(parent))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return parent;
|
|
|
|
|
}
|