diff options
Diffstat (limited to 'matchbox2/core/mb-wm-object.c')
-rw-r--r-- | matchbox2/core/mb-wm-object.c | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/matchbox2/core/mb-wm-object.c b/matchbox2/core/mb-wm-object.c new file mode 100644 index 0000000..09a6ad4 --- /dev/null +++ b/matchbox2/core/mb-wm-object.c @@ -0,0 +1,477 @@ +/* + * Matchbox Window Manager II - A lightweight window manager not for the + * desktop. + * + * Authored By Matthew Allum <mallum@o-hand.com> + * + * Copyright (c) 2005 OpenedHand Ltd - http://o-hand.com + * + * 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. + * + */ + +#include "mb-wm.h" + +#if MBWM_WANT_DEBUG +#include <execinfo.h> +#endif + +static MBWMObjectClassInfo **ObjectClassesInfo = NULL; +static MBWMObjectClass **ObjectClasses = NULL; +static int ObjectClassesAllocated = 0; +static int NObjectClasses = 0; + +#if MBWM_WANT_DEBUG +#define MBWM_OBJECT_TRACE_DEPTH 3 +/* + * Increased for each ref call and decreased for each unref call + */ +MBWMList *alloc_objects = NULL; + +void +mb_wm_object_dump () +{ + MBWMList * l = alloc_objects; + + if (!l) + { + fprintf (stderr, "=== There currently are no allocated objects === \n"); + return; + } + + fprintf (stderr, "=== Currently allocated objects === \n"); + + while (l) + { + int i; + MBWMObject * o = l->data; + const MBWMObjectClass * k = MB_WM_OBJECT_GET_CLASS (o); + + fprintf (stderr, "Object of type %s, allocated from:\n", + k->klass_name); + + + for (i = 1; i < MBWM_OBJECT_TRACE_DEPTH; ++i) + { + char * s = o->trace_strings[i]; + while (s && *s && *s != '(') + s++; + + fprintf (stderr, " %s\n", s); + } + + l = l->next; + } + + fprintf (stderr, "=== Currently allocated objects end === \n"); + +} + +#endif + +#define N_CLASSES_PREALLOC 10 +#define N_CLASSES_REALLOC_STEP 5 + +void +mb_wm_object_init(void) +{ + ObjectClasses = mb_wm_util_malloc0 (sizeof(void*) * N_CLASSES_PREALLOC); + ObjectClassesInfo = mb_wm_util_malloc0 (sizeof(void*) * N_CLASSES_PREALLOC); + + if (ObjectClasses && ObjectClassesInfo) + ObjectClassesAllocated = N_CLASSES_PREALLOC; +} + +static void +mb_wm_object_class_init_recurse (MBWMObjectClass *klass, + MBWMObjectClass *parent) +{ + if (parent->parent) + mb_wm_object_class_init_recurse (klass, parent->parent); + + if (parent->class_init) + parent->class_init (klass); +} + +static void +mb_wm_object_class_init (MBWMObjectClass *klass) +{ + if (klass->parent) + mb_wm_object_class_init_recurse (klass, klass->parent); + + if (klass->class_init) + klass->class_init (klass); +} + +int +mb_wm_object_register_class (MBWMObjectClassInfo *info, + int parent_type, + int flags) +{ + MBWMObjectClass *klass; + + if (NObjectClasses >= ObjectClassesAllocated) + { + int byte_len; + int new_offset; + int new_byte_len; + + new_offset = ObjectClassesAllocated; + ObjectClassesAllocated += N_CLASSES_REALLOC_STEP; + + byte_len = sizeof(void *) * (ObjectClassesAllocated); + new_byte_len = sizeof(void *) * (ObjectClassesAllocated - new_offset); + + ObjectClasses = realloc (ObjectClasses, byte_len); + ObjectClassesInfo = realloc (ObjectClassesInfo, byte_len); + + if (!ObjectClasses || !ObjectClassesInfo) + return 0; + + memset (ObjectClasses + new_offset , 0, new_byte_len); + memset (ObjectClassesInfo + new_offset, 0, new_byte_len); + } + + ObjectClassesInfo[NObjectClasses] = info; + + klass = mb_wm_util_malloc0(info->klass_size); + klass->init = info->instance_init; + klass->destroy = info->instance_destroy; + klass->class_init = info->class_init; + klass->type = NObjectClasses + 1; + + if (parent_type != 0) + klass->parent = ObjectClasses[parent_type-1]; + + ObjectClasses[NObjectClasses] = klass; + + mb_wm_object_class_init (klass); + + return 1 + NObjectClasses++; +} + +void * +mb_wm_object_ref (MBWMObject *this) +{ + if (!this) + { + MBWM_DBG("### Warning: called with NULL ###"); + return this; + } + + this->refcnt++; + + MBWM_TRACE_MSG (OBJ_REF, "### REF ###"); + + return this; +} + +static void +mb_wm_object_destroy_recursive (const MBWMObjectClass * klass, + MBWMObject *this) +{ + /* Destruction needs to happen top to bottom */ + MBWMObjectClass *parent_klass = klass->parent; + + if (klass->destroy) + klass->destroy (this); + + if (parent_klass) + mb_wm_object_destroy_recursive (parent_klass, this); +} + +void +mb_wm_object_unref (MBWMObject *this) +{ + if (!this) + { + MBWM_DBG("### Warning: called with NULL ###"); + return; + } + + + this->refcnt--; + + if (this->refcnt == 0) + { + MBWM_NOTE (OBJ_UNREF, "=== DESTROYING OBJECT type %d ===", + this->klass->type); + + mb_wm_object_destroy_recursive (MB_WM_OBJECT_GET_CLASS (this), + this); + + free (this); + +#if MBWM_WANT_DEBUG + alloc_objects = mb_wm_util_list_remove (alloc_objects, this); +#endif + } +} + +static int +mb_wm_object_init_recurse (MBWMObject *obj, MBWMObjectClass *parent, + va_list vap) +{ + va_list vap2; + + va_copy (vap2, vap); + + if (parent->parent) + if (!mb_wm_object_init_recurse (obj, parent->parent, vap2)) + return 0; + + if (parent->init) + if (!parent->init (obj, vap)) + return 0; + + va_end (vap2); + + return 1; +} + +static int +mb_wm_object_init_object (MBWMObject *obj, va_list vap) +{ + va_list vap2; + + va_copy(vap2, vap); + + if (obj->klass->parent) + if (!mb_wm_object_init_recurse (obj, obj->klass->parent, vap2)) + return 0; + + if (obj->klass->init) + if (!obj->klass->init(obj, vap)) + return 0; + + va_end(vap2); + + return 1; +} + + +MBWMObject* +mb_wm_object_new (int type, ...) +{ + MBWMObjectClassInfo *info; + MBWMObject *obj; + va_list vap; + + va_start(vap, type); + + info = ObjectClassesInfo[type-1]; + + obj = mb_wm_util_malloc0 (info->instance_size); + + obj->klass = MB_WM_OBJECT_CLASS(ObjectClasses[type-1]); + + if (!mb_wm_object_init_object (obj, vap)) + { + free (obj); + return NULL; + } + + + mb_wm_object_ref (obj); + + va_end(vap); + +#if MBWM_WANT_DEBUG + { + void * trace[MBWM_OBJECT_TRACE_DEPTH]; + + alloc_objects = mb_wm_util_list_append (alloc_objects, obj); + obj->trace_depth = backtrace (trace, sizeof(trace)/sizeof(void*)); + obj->trace_strings = backtrace_symbols (trace, obj->trace_depth); + } +#endif + + return obj; +} + +const MBWMObjectClass* +mb_wm_object_get_class (MBWMObject *this) +{ + return this->klass; +} + +unsigned long +mb_wm_object_signal_connect (MBWMObject *obj, + unsigned long signal, + MBWMObjectCallbackFunc func, + void *userdata) +{ + static unsigned long id_counter = 0; + MBWMFuncInfo *func_info; + + MBWM_ASSERT(func != NULL); + + func_info = mb_wm_util_malloc0(sizeof(MBWMFuncInfo)); + func_info->func = (void*)func; + func_info->userdata = userdata; + func_info->data = mb_wm_object_ref (obj); + func_info->signal = signal; + func_info->id = id_counter++; + + obj->callbacks = + mb_wm_util_list_append (obj->callbacks, func_info); + + return func_info->id; +} + +void +mb_wm_object_signal_disconnect (MBWMObject *obj, + unsigned long id) +{ + MBWMList *item = obj->callbacks; + + while (item) + { + MBWMFuncInfo* info = item->data; + + if (info->id == id) + { + MBWMList * prev = item->prev; + MBWMList * next = item->next; + + if (prev) + prev->next = next; + else + obj->callbacks = next; + + if (next) + next->prev = prev; + + mb_wm_object_unref (MB_WM_OBJECT (info->data)); + + free (info); + free (item); + + return; + } + + item = item->next; + } + + MBWM_DBG ("### Warning: did not find signal handler %d ###", id); +} + +void +mb_wm_object_signal_emit (MBWMObject *obj, + unsigned long signal) +{ + MBWMList *item = obj->callbacks; + + while (item) + { + MBWMFuncInfo* info = item->data; + + if (info->signal & signal) + { + if (((MBWMObjectCallbackFunc)info->func) (obj, + signal, + info->userdata)) + { + break; + } + } + + item = item->next; + } +} + +#if 0 + +/* ----- Test code -------- */ + +typedef struct Foo +{ + MBWMObject parent; + + int hello; +} +Foo; + +typedef struct FooClass +{ + MBWMObjectClass parent; + +} +FooClass; + +void +mb_wm_foo_init (MBWMObject *obj) +{ + printf("%s() called\n", __func__); +} + +void +mb_wm_foo_destroy (MBWMObject *obj) +{ + printf("%s() called\n", __func__); +} + +int +mb_wm_foo_get_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (FooClass), + sizeof (Foo), /* Instance */ + mb_wm_foo_init, + mb_wm_foo_destroy, + NULL + }; + + type = mb_wm_object_register_class (&info); + + printf("type: %i\n", type); + } + + return type; +} + +Foo* +mb_wm_foo_new (int val) +{ + Foo *foo; + + foo = (Foo*)mb_wm_object_new (mb_wm_foo_get_class_type ()); + + /* call init */ + + foo->hello = val; + + return foo; +} + + +int +main (int argc, char **argv) +{ + Foo *foo, *foo2; + + mb_wm_object_init(); + + printf("%s() called init, about to call new\n", __func__); + + foo = mb_wm_foo_new (10); + foo2 = mb_wm_foo_new (10); + + printf("%s() foo->hello is %i\n", __func__, foo->hello); + + mb_wm_object_unref (MB_WM_OBJECT(foo)); +} + +#endif |