gambas-source-code/main/gbx/gbx_object.c
Benoît Minisini e0e71dc4f5 [CONFIGURATION]
* NEW: Qt 4.5.0 is now required to compile the gb.qt4 components.

[INTERPRETER]
* NEW: You can now define a non-creatable but auto-creatable class. It 
  means that you cannot instanciate the class, but you can use it
  statically.

[GB.GTK]
* NEW: Screens is a new pseudo-array of all screens.
* NEW: Screen is a new class that represents the geometry of a screen. The
  X, Y, Width and Height properties return the full geometry. The 
  AvailableX, AvailableY, AvailableWidth and AvailableHeight properties 
  return the geometry available to the windows. The screen class can be 
  used statically to get the geometry of the default screen.
  BEWARE: The available geometry is not yet implemented on gb.gtk!
* NEW: Window.Screen is a new property that returns the screen where most 
  of the window is located.
* NEW: Desktop.{X,Y,Width,Height} are four new properties that return the
  available geometry of the default screen. It is an equivalent of
  Screen.{AvailableX,AvailableY,AvailableWidth,AvailableHeight}.

[GB.QT4]
* NEW: Screens is a new pseudo-array of all screens.
* NEW: Screen is a new class that represents the geometry of a screen. The
  X, Y, Width and Height properties return the full geometry. The 
  AvailableX, AvailableY, AvailableWidth and AvailableHeight properties 
  return the geometry available to the windows. The screen class can be 
  used statically to get the geometry of the default screen.
* NEW: Window.Screen is a new property that returns the screen where most 
  of the window is located.
* NEW: Desktop.{X,Y,Width,Height} are four new properties that return the
  available geometry of the default screen. It is an equivalent of
  Screen.{AvailableX,AvailableY,AvailableWidth,AvailableHeight}.


git-svn-id: svn://localhost/gambas/trunk@3413 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2010-12-30 01:52:40 +00:00

508 lines
10 KiB
C

/***************************************************************************
gbx_object.c
(c) 2000-2009 Benoît 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 2, 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_observer.h"
#include "gbx_c_array.h"
#include "gbx_struct.h"
#include "gbx_object.h"
#if DEBUG_REF
const char *OBJECT_ref_where = 0;
#endif
void **OBJECT_set_pointer = NULL;
static OBJECT *EventObject = NULL;
void *OBJECT_new(CLASS *class, const char *name, OBJECT *parent)
{
OBJECT *object;
ALLOC_ZERO(&object, class->size, "OBJECT_new");
object->class = class;
#if DEBUG_REF
object->ref = 0;
OBJECT_REF(object, "OBJECT_new");
#else
object->ref = 1;
#endif
class->count++;
OBJECT_attach(object, parent, name);
return 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
static void call_attach_special_method(CLASS *class, void *ob, void *parent, const char *name)
{
STACK_check(2);
SP->_object.class = OBJECT_class(parent);
SP->_object.object = parent;
PUSH();
if (name)
{
SP->type = T_CSTRING;
SP->_string.addr = (char *)name;
SP->_string.start = 0;
SP->_string.len = strlen(name);
}
else
{
SP->type = T_NULL;
}
SP++;
EXEC_special(SPEC_ATTACH, class, ob, 2, TRUE);
}
void OBJECT_detach(OBJECT *ob)
{
CLASS *class = OBJECT_class(ob);
OBJECT *parent;
OBJECT_EVENT *ev;
bool lock;
if (!class->is_observer && class->n_event == 0)
return;
ev = (OBJECT_EVENT *)((char *)ob + class->off_event);
//if (!ev->parent)
// return;
// Do not free the observers there
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");
/* Avoids an infinite recursion, if freeing the parent implies freeing the object */
parent = OBJECT_parent(ob);
if (parent)
{
if (class->special[SPEC_ATTACH] != NO_SYMBOL)
call_attach_special_method(class, ob, parent, NULL);
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
OBJECT_UNREF(parent, "OBJECT_detach");
}
}
static void remove_observers(OBJECT *ob)
{
CLASS *class = OBJECT_class(ob);
OBJECT_EVENT *ev;
COBSERVER *obs, *next;
//fprintf(stderr, "Remove observers: %s %p\n", class->name, ob);
if (!class->is_observer && class->n_event == 0)
return;
ev = (OBJECT_EVENT *)((char *)ob + class->off_event);
obs = ev->observer;
ev->observer = NULL;
while (obs)
{
next = obs->list.next;
#if DEBUG_EVENT
fprintf(stderr, "Remove observer %p %d: %p: %p %p\n", obs, (int)obs->ob.ref, ob, obs->object, obs->proxy);
#endif
OBJECT_UNREF(obs, "remove_observers");
obs = next;
}
//ev->observer = NULL;
}
void OBJECT_attach(OBJECT *ob, OBJECT *parent, const char *name)
{
CLASS *class = OBJECT_class(ob);
OBJECT_EVENT *ev;
bool lock;
if (!name)
return;
if (!class->is_observer && class->n_event == 0)
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;
if (class->special[SPEC_ATTACH] != NO_SYMBOL)
call_attach_special_method(class, ob, parent, name);
//dump_attach("OBJECT_attach");
}
void OBJECT_free(CLASS *class, OBJECT *ob)
{
OBJECT_detach(ob);
remove_observers(ob);
class->count--;
#if DEBUG_REF
ob->class = FREE_MARK;
#endif
FREE(&ob, "OBJECT_free");
}
bool OBJECT_comp_value(VALUE *ob1, VALUE *ob2)
{
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);
}
void OBJECT_release_static(CLASS *class, CLASS_VAR *var, int nelt, char *data)
{
static void *jump[17] = {
&&__NEXT, &&__NEXT, &&__NEXT, &&__NEXT, &&__NEXT, &&__NEXT, &&__NEXT, &&__NEXT, &&__NEXT,
&&__STRING, &&__NEXT, &&__NEXT, &&__VARIANT, &&__ARRAY, &&__STRUCT, &&__NEXT, &&__OBJECT
};
CTYPE type;
while (nelt--)
{
#if TRACE_MEMORY
if (var->type.id == T_STRING || var->type.id == T_OBJECT)
fprintf(stderr, "release_static: %s [%d] trying %p\n", class->name, i, (*(void **)&data[var->pos]));
#endif
type = var->type;
goto *jump[type.id];
__STRING:
STRING_unref((char **)&data[var->pos]);
goto __NEXT;
__OBJECT:
OBJECT_UNREF(*((void **)&data[var->pos]), "release");
goto __NEXT;
__VARIANT:
VARIANT_free((VARIANT *)&data[var->pos]);
goto __NEXT;
__ARRAY:
CARRAY_release_static(class, class->load->array[type.value], &data[var->pos]);
goto __NEXT;
__STRUCT:
{
CLASS *sclass = class->load->class_ref[type.value];
OBJECT_release_static(sclass, sclass->load->dyn, sclass->load->n_dyn, &data[var->pos]);
}
__NEXT:
var++;
}
}
static void release(CLASS *class, OBJECT *ob)
{
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
{
if (CLASS_is_struct(class))
{
if (((CSTRUCT *)ob)->ref)
{
CSTRUCT_release((CSTRUCT *)ob);
return;
}
data = (char *)ob + sizeof(CSTRUCT);
}
else
data = (char *)ob;
var = class->load->dyn;
nelt = class->load->n_dyn;
}
OBJECT_release_static(class, var, nelt, data);
}
void OBJECT_release(CLASS *class, OBJECT *ob)
{
#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
}
void OBJECT_exit(void)
{
#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
}
static void *_object;
static char *_object_name;
static void error_OBJECT_create(void)
{
OBJECT_UNREF_KEEP(_object, "OBJECT_create");
EVENT_leave_name(_object_name);
}
void *OBJECT_create(CLASS *class, const char *name, void *parent, int nparam)
{
void *ob;
void *save;
char *save_name;
// The "no create" flag only concerns users of NEW
//if (class->no_create)
// THROW(E_CSTATIC, class->name);
save = _object;
save_name = _object_name;
ON_ERROR(error_OBJECT_create)
{
_object_name = EVENT_enter_name(name);
_object = ob = OBJECT_new(class, name, parent);
if (OBJECT_set_pointer)
{
*OBJECT_set_pointer = ob;
OBJECT_set_pointer = NULL;
}
OBJECT_lock(ob, TRUE);
EXEC_special_inheritance(SPEC_NEW, class, ob, nparam, TRUE);
OBJECT_lock(ob, FALSE);
error_OBJECT_create();
}
END_ERROR
_object = save;
_object_name = save_name;
return ob;
}
/* FIXME: The _new are methods called differently from EXEC_special_inheritance */
void *OBJECT_create_native(CLASS *class, VALUE *param)
{
CLASS_DESC *desc;
short index;
void *object;
object = OBJECT_new(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;
}
OBJECT_UNREF_KEEP(object, "OBJECT_create");
return object;
}
void OBJECT_lock(OBJECT *object, bool block)
{
CLASS *class;
if (!object)
return;
class = object->class;
if (class->is_observer)
{
COBSERVER_lock((COBSERVER *)object, block);
return;
}
if (class->n_event == 0)
return;
// fprintf(stderr, "OBJECT_lock: (%s %p) %s\n", class->name, object, block ? "lock" : "unlock");
if (block)
OBJECT_event(object)->parent = (OBJECT *)((intptr_t)OBJECT_event(object)->parent | 1);
else
OBJECT_event(object)->parent = (OBJECT *)((intptr_t)OBJECT_event(object)->parent & ~1);
}
bool OBJECT_is_locked(OBJECT *object)
{
CLASS *class;
if (!object)
return FALSE;
class = object->class;
if (class->is_observer)
return COBSERVER_is_locked((COBSERVER *)object);
if (class->n_event == 0)
return FALSE;
return (((intptr_t)OBJECT_event(object)->parent & 1) != 0);
}
OBJECT *OBJECT_parent(void *object)
{
CLASS *class = OBJECT_class(object);
if (!class->is_observer && class->n_event == 0)
return NULL;
return ((OBJECT *)((intptr_t)OBJECT_event(object)->parent & ~1));
}
OBJECT *OBJECT_active_parent(void *object)
{
OBJECT *parent = OBJECT_parent(object);
if (!parent || OBJECT_is_locked((OBJECT *)object) || OBJECT_is_locked(parent))
return NULL;
return parent;
}