Enlightenment CVS committal Author : moom Project : e17 Module : proto
Dir : e17/proto/etk/src/lib Modified Files: etk_combobox.c etk_main.c etk_object.c etk_object.h etk_widget.c Log Message: * Now etk_object_destroy() doesn't frees the object directly, but queues it for freeing. It solves all sort of problems =================================================================== RCS file: /cvs/e/e17/proto/etk/src/lib/etk_combobox.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -3 -r1.23 -r1.24 --- etk_combobox.c 8 Aug 2006 18:51:22 -0000 1.23 +++ etk_combobox.c 13 Aug 2006 19:20:28 -0000 1.24 @@ -693,6 +693,7 @@ /* Destroys the combobox */ static void _etk_combobox_destructor(Etk_Combobox *combobox) { + Etk_Combobox_Item *item; int i; if (!combobox) @@ -701,7 +702,13 @@ combobox->selected_item = NULL; combobox->active_item = NULL; while (combobox->items) - etk_object_destroy(ETK_OBJECT(combobox->items->data)); + { + item = ETK_COMBOBOX_ITEM(combobox->items->data); + + item->combobox = NULL; + etk_object_destroy(ETK_OBJECT(item)); + combobox->items = evas_list_remove_list(combobox->items, combobox->items); + } free(combobox->active_item_children); for (i = 0; i < combobox->num_cols; i++) =================================================================== RCS file: /cvs/e/e17/proto/etk/src/lib/etk_main.c,v retrieving revision 1.29 retrieving revision 1.30 diff -u -3 -r1.29 -r1.30 --- etk_main.c 5 Aug 2006 02:37:25 -0000 1.29 +++ etk_main.c 13 Aug 2006 19:20:28 -0000 1.30 @@ -44,12 +44,12 @@ /** * @brief Initializes Etk. This function needs to be called before any other call to an etk_* function. @n - * You can call safely etk_init() several times, it will have an effect only the first time you call it. The other times, + * You can call safely etk_init() several times, it will only have an effect the first time you call it. The other times, * it will just increment a counter. etk_shutdown() will decrement this counter and will effectively shutdown Etk when * the counter reaches 0. So you need to call etk_shutdown() the same number of times as etk_init(). - * @param argc the location of the "argc" paramater passed to main(). It is used to parse the arguments specific to Etk. + * @param argc the location of the "argc" parameter passed to main(). It is used to parse the arguments specific to Etk. * It can be set to NULL. - * @param argv the location of the "argv" paramater passed to main(). It is used to parse the arguments specific to Etk. + * @param argv the location of the "argv" parameter passed to main(). It is used to parse the arguments specific to Etk. * It can be set to NULL. * @return Returns the number of times Etk has been initialized, or 0 on failure * @note It initializes Evas, Ecore and Edje so you don't need to initialize them after an etk_init() @@ -132,8 +132,8 @@ _etk_main_init_count--; if (_etk_main_init_count == 0) { - /* Shutdown the subsystem of Etk */ - etk_object_destroy_all_objects(); + /* Shutdown the subsystems of Etk */ + etk_object_shutdown(); etk_signal_shutdown(); etk_type_shutdown(); @@ -143,7 +143,8 @@ etk_engine_shutdown(); etk_theme_shutdown(); - _etk_main_toplevel_widgets = evas_list_free(_etk_main_toplevel_widgets); + evas_list_free(_etk_main_toplevel_widgets); + _etk_main_toplevel_widgets = NULL; /* Shutdown the EFL*/ edje_shutdown(); @@ -195,6 +196,8 @@ if (_etk_main_init_count <= 0) return; + + etk_object_purge(); /* TODO: only update the toplevel widgets that need to be updated */ for (l = _etk_main_toplevel_widgets; l; l = l->next) @@ -240,7 +243,7 @@ } /** - * @brief Gets the list of the created toplevel widgets (windows, ...) + * @brief Gets the list of the created toplevel widgets (windows, embed widgets, ...) * @return Returns the list of the created toplevel widgets */ Evas_List *etk_main_toplevel_widgets_get() =================================================================== RCS file: /cvs/e/e17/proto/etk/src/lib/etk_object.c,v retrieving revision 1.25 retrieving revision 1.26 diff -u -3 -r1.25 -r1.26 --- etk_object.c 8 Aug 2006 18:03:01 -0000 1.25 +++ etk_object.c 13 Aug 2006 19:20:28 -0000 1.26 @@ -27,10 +27,12 @@ static void _etk_object_constructor(Etk_Object *object); static void _etk_object_destructor(Etk_Object *object); +static void _etk_object_free(Etk_Object *object); static Evas_Bool _etk_object_notification_callbacks_free_cb(Evas_Hash *hash, const char *key, void *data, void *fdata); static Evas_Bool _etk_object_data_free_cb(Evas_Hash *hash, const char *key, void *data, void *fdata); -static Evas_List *_etk_object_created_objects = NULL; +static Etk_Object *_etk_object_objects = NULL; +static Etk_Object *_etk_object_last_object = NULL; static Etk_Signal *_etk_object_signals[ETK_OBJECT_NUM_SIGNALS]; /************************** @@ -40,6 +42,32 @@ **************************/ /** + * @internal + * @brief Shutdowns the object system: it frees all the created objects + */ +void etk_object_shutdown() +{ + while (_etk_object_objects) + _etk_object_free(_etk_object_objects); +} +/** + * @internal + * @brief Frees the objects that have been marked as "destroyed". + * It's called at the start of each iteration of the main loop + */ +void etk_object_purge() +{ + Etk_Object *object, *next; + + for (object = _etk_object_objects; object; object = next) + { + next = object->next; + if (object->destroy_me) + _etk_object_free(object); + } +} + +/** * @brief Gets the type of an Etk_Object * @return Returns the type of an Etk_Object */ @@ -99,10 +127,9 @@ if (!object_type) return NULL; - + new_object = malloc(object_type->type_size); new_object->type = object_type; - _etk_object_created_objects = evas_list_append(_etk_object_created_objects, new_object); etk_type_object_construct(object_type, new_object); va_copy(args2, args); @@ -113,28 +140,29 @@ } /** - * @brief Destroys the object: if first emits the "destroyed" signal, sets the weak pointers to NULL and then - * calls the destructors (from the destructor of the more derived class to the destructor of the ultimate base class) + * @brief Destroys the object: it first sets the weak pointers to NULL, emits the "destroyed" signal, and then + * queues the object in the list of objects to free. Thus, the destructors will only be called at the beginning of the + * next main loop iteration (from the destructor of the more derived class to the destructor of the ultimate base class). * @param object the object to destroy + * @warning You should not assume that this function will call directly the destructors of the object! */ void etk_object_destroy(Etk_Object *object) { - if (!object) + void **weak_pointer; + + if (!object || object->destroy_me) return; + /* Sets the weak pointers to NULL */ + while (object->weak_pointers_list) + { + weak_pointer = object->weak_pointers_list->data; + *weak_pointer = NULL; + object->weak_pointers_list = evas_list_remove_list(object->weak_pointers_list, object->weak_pointers_list); + } + + object->destroy_me = ETK_TRUE; etk_signal_emit(_etk_object_signals[ETK_OBJECT_DESTROYED_SIGNAL], object, NULL); - etk_type_destructors_call(object->type, object); - _etk_object_created_objects = evas_list_remove(_etk_object_created_objects, object); - free(object); -} - -/** - * @brief Destroys all the created objects. You do not need to call it manually, etk_shutdown() calls it automatically - */ -void etk_object_destroy_all_objects() -{ - while (_etk_object_created_objects) - etk_object_destroy(ETK_OBJECT(_etk_object_created_objects->data)); } /** @@ -223,7 +251,7 @@ */ void etk_object_weak_pointer_add(Etk_Object *object, void **pointer_location) { - if (!object || !pointer_location) + if (!object || !pointer_location || object->destroy_me) return; object->weak_pointers_list = evas_list_append(object->weak_pointers_list, pointer_location); } @@ -571,22 +599,23 @@ object->after_signal_callbacks_list = NULL; object->notification_callbacks_hash = NULL; object->weak_pointers_list = NULL; + object->destroy_me = ETK_FALSE; + + /* Append the new object to the list */ + object->prev = _etk_object_last_object; + object->next = NULL; + if (!_etk_object_objects) + _etk_object_objects = object; + if (_etk_object_last_object) + _etk_object_last_object->next = object; + _etk_object_last_object = object; } /* Destroys the object */ static void _etk_object_destructor(Etk_Object *object) { - void **weak_pointer; - if (!object) return; - - while (object->weak_pointers_list) - { - weak_pointer = object->weak_pointers_list->data; - *weak_pointer = NULL; - object->weak_pointers_list = evas_list_remove_list(object->weak_pointers_list, object->weak_pointers_list); - } evas_hash_foreach(object->data_hash, _etk_object_data_free_cb, NULL); evas_hash_free(object->data_hash); @@ -614,6 +643,28 @@ * **************************/ +/* Frees the object: it calls the destructors (from the destructor of the more derived class + * to the destructor of the ultimate base class) and frees the allocated memory */ +static void _etk_object_free(Etk_Object *object) +{ + if (!object) + return; + + etk_object_destroy(object); + etk_type_destructors_call(object->type, object); + + if (object->prev) + object->prev->next = object->next; + if (object->next) + object->next->prev = object->prev; + if (object == _etk_object_objects) + _etk_object_objects = object->next; + if (object == _etk_object_last_object) + _etk_object_last_object = object->prev; + + free(object); +} + /* Frees a list of notification callbacks (called by _etk_object_destructor()) */ static Evas_Bool _etk_object_notification_callbacks_free_cb(Evas_Hash *hash, const char *key, void *data, void *fdata) { @@ -671,9 +722,11 @@ * etk_object_new() automatically calls the corresponding constructors of the object, from the constructor of * the base class to the constructor of the more derived class. @n * - * You can also destroy an object with etk_object_destroy(). It sets the weak pointers of the object to NULL - * (see etk_object_weak_pointer_add()) and then calls the destructors from the destructor of the more derived class - * to the destructor of the ultimate base class. @n @n + * You can then destroy the object with etk_object_destroy(): it sets the weak pointers of the object to NULL + * (see etk_object_weak_pointer_add()), emits the "destroyed" signal and queues the object for freeing. Thus, the + * destructors will only be called at the beginning of the next main loop iteration (from the destructor of the more + * derived class to the destructor of the ultimate base class). So, you should not assume that etk_object_destroy() + * will directly call the destructors. @n @n * * <b>Signal concept:</b> @n * Each object has a list of signals that can be connected to one or several callbacks. The callbacks connected to =================================================================== RCS file: /cvs/e/e17/proto/etk/src/lib/etk_object.h,v retrieving revision 1.9 retrieving revision 1.10 diff -u -3 -r1.9 -r1.10 --- etk_object.h 8 Aug 2006 18:03:01 -0000 1.9 +++ etk_object.h 13 Aug 2006 19:20:28 -0000 1.10 @@ -51,13 +51,19 @@ Evas_List *after_signal_callbacks_list; Evas_Hash *notification_callbacks_hash; Evas_List *weak_pointers_list; + Etk_Bool destroy_me; + + Etk_Object *prev; + Etk_Object *next; }; +void etk_object_shutdown(); +void etk_object_purge(); + Etk_Type *etk_object_type_get(); Etk_Object *etk_object_new(Etk_Type *object_type, const char *first_property, ...); Etk_Object *etk_object_new_valist(Etk_Type *object_type, const char *first_property, va_list args); void etk_object_destroy(Etk_Object *object); -void etk_object_destroy_all_objects(); Etk_Object *etk_object_check_cast(Etk_Object *object, Etk_Type *type); Etk_Type *etk_object_object_type_get(Etk_Object *object); =================================================================== RCS file: /cvs/e/e17/proto/etk/src/lib/etk_widget.c,v retrieving revision 1.69 retrieving revision 1.70 diff -u -3 -r1.69 -r1.70 --- etk_widget.c 8 Aug 2006 18:51:22 -0000 1.69 +++ etk_widget.c 13 Aug 2006 19:20:28 -0000 1.70 @@ -87,6 +87,7 @@ static void _etk_widget_constructor(Etk_Widget *widget); static void _etk_widget_destructor(Etk_Widget *widget); +static void _etk_widget_destroyed_cb(Etk_Object *object, void *data); static void _etk_widget_property_set(Etk_Object *object, int property_id, Etk_Property_Value *value); static void _etk_widget_property_get(Etk_Object *object, int property_id, Etk_Property_Value *value); @@ -1927,6 +1928,7 @@ widget->dnd_types = NULL; widget->dnd_types_num = 0; + etk_signal_connect("destroyed", ETK_OBJECT(widget), ETK_CALLBACK(_etk_widget_destroyed_cb), NULL); etk_signal_connect("mouse_in", ETK_OBJECT(widget), ETK_CALLBACK(_etk_widget_signal_mouse_in_cb), NULL); etk_signal_connect("mouse_out", ETK_OBJECT(widget), ETK_CALLBACK(_etk_widget_signal_mouse_out_cb), NULL); etk_signal_connect("mouse_down", ETK_OBJECT(widget), ETK_CALLBACK(_etk_widget_signal_mouse_down_cb), NULL); @@ -1946,11 +1948,6 @@ return; _etk_widget_unrealize(widget); - - /* Remove the children */ - while (widget->children) - etk_object_destroy(ETK_OBJECT(widget->children->data)); - evas_list_free(widget->focus_order); etk_widget_parent_set(widget, NULL); while (widget->theme_children) @@ -1972,6 +1969,27 @@ free(widget->theme_file); free(widget->theme_group); +} + +/* Called when etk_object_destroy() is called on the widget + * We use this to destroy the children of the widget because ... TODO */ +void _etk_widget_destroyed_cb(Etk_Object *object, void *data) +{ + Etk_Widget *widget; + Etk_Widget *child; + + if (!(widget = ETK_WIDGET(object))) + return; + + /* Remove the children */ + while (widget->children) + { + child = ETK_WIDGET(widget->children->data); + + etk_widget_parent_set(child, NULL); + etk_object_destroy(ETK_OBJECT(child)); + } + widget->focus_order = evas_list_free(widget->focus_order); } /* Sets the property whose id is "property_id" to the value "value" */ ------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs