changeset 192:54fdc2a65242

Remove factory from observer APIs. - Save factory that used to new a subject as subject's attribute. - Get factory from subject himself instead of passing as an argument. - It make API of observer more simple and clean.
author Thinker K.F. Li <thinker@branda.to>
date Tue, 18 Nov 2008 21:42:30 +0800
parents 18f8c3126cdb
children 923d91dfb6af bcad1ccdf45c
files examples/calculator/main.c examples/svg2code_ex/main.c examples/tank/tank_main.c include/mb_animate.h include/mb_observer.h src/X_supp.c src/animate.c src/observer.c src/redraw_man.c
diffstat 9 files changed, 88 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/examples/calculator/main.c	Tue Nov 18 13:55:09 2008 +0800
+++ b/examples/calculator/main.c	Tue Nov 18 21:42:30 2008 +0800
@@ -151,22 +151,18 @@
 
 static void setup_observers(calc_data_t *calc_data) {
     calculator_scr_t *calculator_scr;
-    ob_factory_t *factory;
     subject_t *subject;
     coord_t *coord;
-    redraw_man_t *rdman;
     int off;
     int i;
 
     calculator_scr = calc_data->code;
-    rdman = X_MB_rdman(calc_data->rt);
-    factory = rdman_get_ob_factory(rdman);
 
     for(i = 0; i < 16; i++) {
 	off = tgt_list[i].off;
 	coord = OFF2TYPE(calculator_scr, off, coord_t *);
 	subject = coord_get_mouse_event(coord);
-	subject_add_observer(factory, subject, buttons_handler, calc_data);
+	subject_add_observer(subject, buttons_handler, calc_data);
     }
 }
 
--- a/examples/svg2code_ex/main.c	Tue Nov 18 13:55:09 2008 +0800
+++ b/examples/svg2code_ex/main.c	Tue Nov 18 21:42:30 2008 +0800
@@ -48,7 +48,6 @@
     X_MB_runtime_t *rt;
     redraw_man_t *rdman;
     svg2code_ex_t *svg2code;
-    ob_factory_t *factory;
     subject_t *subject;
     ex_rt_t ex_rt;
 
@@ -64,18 +63,14 @@
     svg2code = svg2code_ex_new(rdman, rdman->root_coord);
 
     /*
-     * Get observer factory
-     */
-    factory = rdman_get_ob_factory(rdman);
-    /*
      * Register observers to subjects of events for objects.
      */
     subject = coord_get_mouse_event(svg2code->file_button);
     ex_rt.rt = rt;
     ex_rt.code = svg2code;
-    subject_add_observer(factory, subject, file_button_handler, &ex_rt);
+    subject_add_observer(subject, file_button_handler, &ex_rt);
     subject = coord_get_mouse_event(svg2code->file_menu);
-    subject_add_observer(factory, subject, file_menu_handler, &ex_rt);
+    subject_add_observer(subject, file_menu_handler, &ex_rt);
 
     /*
      * Start handle connections, includes one to X server.
--- a/examples/tank/tank_main.c	Tue Nov 18 13:55:09 2008 +0800
+++ b/examples/tank/tank_main.c	Tue Nov 18 21:42:30 2008 +0800
@@ -266,8 +266,7 @@
 
     /* Clean program when it is completed. */
     comp_sub = mb_progm_get_complete(progm);
-    subject_add_observer(factory, comp_sub,
-			 clean_tank_progm_handler, tank);
+    subject_add_observer(comp_sub, clean_tank_progm_handler, tank);
 
     get_now(&now);
     mb_progm_start(progm, tman, &now);
@@ -492,7 +491,6 @@
     mb_action_t *act;
     mb_timeval_t start, playing;
     mb_timeval_t now, next;
-    ob_factory_t *factory;
     mb_tman_t *tman;
     subject_t *subject;
     static int map_xy_adj[][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
@@ -546,8 +544,7 @@
     
     /*! \todo Simplify the procdure of using observer pattern. */
     subject = mb_progm_get_complete(progm);
-    factory = rdman_get_ob_factory(rdman);
-    subject_add_observer(factory, subject, bullet_go_out_map, tank);
+    subject_add_observer(subject, bullet_go_out_map, tank);
 
     get_now(&now);
     MB_TIMEVAL_CP(&bullet->start_time, &now);
@@ -614,16 +611,14 @@
     X_MB_runtime_t *mb_rt;
     subject_t *kbevents;
     redraw_man_t *rdman;
-    ob_factory_t *factory;
 
     mb_rt = tank_rt->mb_rt;
     kbevents = X_MB_kbevents(mb_rt);
 
     rdman = X_MB_rdman(mb_rt);
-    factory = rdman_get_ob_factory(rdman);
 
     tank_rt->kb_observer =
-	subject_add_observer(factory, kbevents, keyboard_handler, tank_rt);
+	subject_add_observer(kbevents, keyboard_handler, tank_rt);
 }
 
 /*! \brief Make coord objects to decorate elfs (tanks).
--- a/include/mb_animate.h	Tue Nov 18 13:55:09 2008 +0800
+++ b/include/mb_animate.h	Tue Nov 18 21:42:30 2008 +0800
@@ -44,6 +44,7 @@
 			   mb_timeval_t *now);
 extern void mb_progm_abort(mb_progm_t *progm);
 extern subject_t *mb_progm_get_complete(mb_progm_t *progm);
+extern void mb_progm_free_completed(mb_progm_t *progm);
 
 /*! \defgroup ani_actions Animation Actions
  * @{
--- a/include/mb_observer.h	Tue Nov 18 13:55:09 2008 +0800
+++ b/include/mb_observer.h	Tue Nov 18 21:42:30 2008 +0800
@@ -35,6 +35,7 @@
     int obj_type;		/*!< \brief type of object (a.k.a. OBJT_*). */
     void *obj;			/*!< \brief the object this subject for. */
     int flags;
+    ob_factory_t *factory;
     STAILQ(observer_t) observers;
 };
 /*! \brief Flag that make a subject to propagate events to parents. */
@@ -77,14 +78,11 @@
 
 extern subject_t *subject_new(ob_factory_t *factory,
 			      void *obj, int obj_type);
-extern void subject_free(ob_factory_t *factory, subject_t *subject);
-extern void subject_notify(ob_factory_t *factory,
-			   subject_t *subject, event_t *evt);
-extern observer_t *subject_add_observer(ob_factory_t *factory,
-					subject_t *subject,
+extern void subject_free(subject_t *subject);
+extern void subject_notify(subject_t *subject, event_t *evt);
+extern observer_t *subject_add_observer(subject_t *subject,
 					evt_handler hdr, void *arg);
-extern void subject_remove_observer(ob_factory_t *factory,
-				    subject_t *subject,
+extern void subject_remove_observer(subject_t *subject,
 				    observer_t *observer);
 
 
--- a/src/X_supp.c	Tue Nov 18 13:55:09 2008 +0800
+++ b/src/X_supp.c	Tue Nov 18 21:42:30 2008 +0800
@@ -80,13 +80,14 @@
     kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB);
     if(kbinfo->kbevents == NULL)
 	return ERR;
+    /*! \todo Make sure ob_factory is still need. */
     kbinfo->ob_factory = factory;
 
     return OK;
 }
 
 static void X_kb_destroy(X_kb_info_t *kbinfo) {
-    subject_free(kbinfo->ob_factory, kbinfo->kbevents);
+    subject_free(kbinfo->kbevents);
     XFree(kbinfo->syms);
 }
 
@@ -107,7 +108,7 @@
     event.keycode = code;
     event.sym = sym;
 
-    subject_notify(kbinfo->ob_factory, kbinfo->kbevents, &event.event);
+    subject_notify(kbinfo->kbevents, &event.event);
 }
 
 /* @} */
@@ -151,7 +152,6 @@
 			  unsigned int button) {
     mouse_event_t mouse_event;
     subject_t *subject;
-    ob_factory_t *factory;
 
     mouse_event.event.type = etype;
     mouse_event.x = x;
@@ -160,9 +160,8 @@
     mouse_event.button = button;
     
     subject = sh_get_mouse_event_subject(shape);
-    factory = rdman_get_ob_factory(rdman);
     
-    subject_notify(factory, subject, (event_t *)&mouse_event);
+    subject_notify(subject, (event_t *)&mouse_event);
 }
 
 /*! \brief Dispatch all X events in the queue.
--- a/src/animate.c	Tue Nov 18 13:55:09 2008 +0800
+++ b/src/animate.c	Tue Nov 18 21:42:30 2008 +0800
@@ -140,9 +140,6 @@
     int n_words;
     mb_word_t *word;
     mb_action_t *cur_act;
-#ifndef UNITTEST
-    ob_factory_t *factory;
-#endif /* UNITTEST */
     int i;
 
     n_words = progm->n_words;
@@ -157,8 +154,7 @@
     }
 
 #ifndef UNITTEST
-    factory = rdman_get_ob_factory(progm->rdman);
-    subject_free(factory, progm->complete);
+    subject_free(progm->complete);
 #endif /* UNITTEST */
 
     free(progm);
@@ -238,7 +234,6 @@
 #ifndef UNITTEST
     /*! \todo Leverage aspective programming to prevent problem of unittest.
      */
-    ob_factory_t *factory;
     mb_progm_complete_t comp_evt;
 #endif /* UNITTEST */
     mb_timeval_t next_tmo;
@@ -294,11 +289,10 @@
     } else {
 	/* Make program to complete. */
 #ifndef UNITTEST
-	factory = rdman_get_ob_factory(progm->rdman);
 	comp_evt.event.type = EVT_PROGM_COMPLETE;
 	comp_evt.event.tgt = comp_evt.event.cur_tgt = progm->complete;
 	comp_evt.progm = progm;
-	subject_notify(factory, progm->complete, &comp_evt.event);
+	subject_notify(progm->complete, &comp_evt.event);
 #endif /* UNITTEST */
 	progm->cur_timer = NULL;
     }
@@ -352,6 +346,20 @@
     return progm->complete;
 }
 
+static void _free_completed_hdlr(event_t *event, void *arg) {
+    mb_progm_t *progm = (mb_progm_t *)arg;
+
+    mb_progm_free(progm);
+}
+
+/*! \brief The program should be freed after completed. */
+void mb_progm_free_completed(mb_progm_t *progm) {
+    subject_t *complete;
+
+    complete = mb_progm_get_complete(progm);
+    subject_add_observer(complete, _free_completed_hdlr, progm);
+}
+
 #ifdef UNITTEST
 
 #include <CUnit/Basic.h>
--- a/src/observer.c	Tue Nov 18 13:55:09 2008 +0800
+++ b/src/observer.c	Tue Nov 18 21:42:30 2008 +0800
@@ -19,13 +19,16 @@
     subject->flags = 0;
     STAILQ_INIT(subject->observers);
 
+    subject->factory = factory;
+
     return subject;
 }
 
 /*!
  * \todo Keep ob_factory following subject objects.
  */
-void subject_free(ob_factory_t *factory, subject_t *subject) {
+void subject_free(subject_t *subject) {
+    ob_factory_t *factory = subject->factory;
     observer_t *observer;
 
     ASSERT(!(subject->flags & SUBF_FREE));
@@ -45,7 +48,8 @@
 }
 
 
-void subject_notify(ob_factory_t *factory, subject_t *subject, event_t *evt) {
+void subject_notify(subject_t *subject, event_t *evt) {
+    ob_factory_t *factory = subject->factory;
     observer_t *observer;
 
     evt->tgt = subject;
@@ -66,7 +70,7 @@
 
 	subject->flags &= ~SUBF_BUSY;
 	if(subject->flags & SUBF_FREE)
-	    subject_free(factory, subject);
+	    subject_free(subject);
 
 	if(subject->flags & SUBF_STOP_PROPAGATE)
 	    break;
@@ -76,9 +80,9 @@
 
 }
 
-observer_t *subject_add_observer(ob_factory_t *factory,
-				 subject_t *subject,
+observer_t *subject_add_observer(subject_t *subject,
 				 evt_handler hdr, void *arg) {
+    ob_factory_t *factory = subject->factory;
     observer_t *observer;
 
     observer = factory->observer_alloc(factory);
@@ -92,9 +96,10 @@
     return observer;
 }
 
-void subject_remove_observer(ob_factory_t *factory,
-			     subject_t *subject,
+void subject_remove_observer(subject_t *subject,
 			     observer_t *observer) {
+    ob_factory_t *factory = subject->factory;
+
     STAILQ_REMOVE(subject->observers, observer_t, next, observer);
     factory->observer_free(factory, observer);
 }
@@ -154,20 +159,18 @@
 
     subject = subject_new(&test_factory, NULL, 0);
     subject->flags |= SUBF_STOP_PROPAGATE;
-    observer[0] = subject_add_observer(&test_factory, subject,
-				       handler, &cnt);
-    observer[1] = subject_add_observer(&test_factory, subject,
-				       handler, &cnt);
+    observer[0] = subject_add_observer(subject, handler, &cnt);
+    observer[1] = subject_add_observer(subject, handler, &cnt);
 
     evt.type = EVT_MOUSE_OUT;
     evt.tgt = NULL;
     evt.cur_tgt = NULL;
-    subject_notify(&test_factory, subject, &evt);
+    subject_notify(subject, &evt);
     CU_ASSERT(cnt == 2);
 
-    subject_remove_observer(&test_factory, subject, observer[0]);
-    subject_remove_observer(&test_factory, subject, observer[1]);
-    subject_free(&test_factory, subject);
+    subject_remove_observer(subject, observer[0]);
+    subject_remove_observer(subject, observer[1]);
+    subject_free(subject);
 }
 
 CU_pSuite get_observer_suite(void) {
--- a/src/redraw_man.c	Tue Nov 18 13:55:09 2008 +0800
+++ b/src/redraw_man.c	Tue Nov 18 21:42:30 2008 +0800
@@ -445,7 +445,7 @@
 	geo_detach_coord(geo, shape->coord);
 	sh_detach_coord(shape);
 	sh_detach_geo(shape);
-	subject_free(&rdman->ob_factory, geo->mouse_event);
+	subject_free(geo->mouse_event);
 	elmpool_elm_free(rdman->geo_pool, geo);
     }
     STAILQ_REMOVE(rdman->shapes, shape_t, sh_next, shape);
@@ -547,60 +547,66 @@
     return coord;
 }
 
+static int rdman_coord_free_postponse(redraw_man_t *rdman, coord_t *coord) {
+    int r;
+
+    if(coord->flags & COF_FREE)
+	return ERR;
+    
+    coord->flags |= COF_FREE;
+    coord_hide(coord);
+    if(!(coord->flags & COF_DIRTY)) {
+	r = add_dirty_coord(rdman, coord);
+	if(r != OK)
+	    return ERR;
+    }
+    r = add_free_obj(rdman, coord, (free_func_t)rdman_coord_free);
+    if(r != OK)
+	return ERR;
+    return OK;
+}
+
 /*! \brief Free a coord of a redraw_man_t object.
  *
+ * All children and members should be freed before parent being freed.
+ *
  * \param coord is a coord_t without children and members.
  * \return 0 for successful, -1 for error.
  *
- * \note Removing coords when the rdman is dirty, the removing is postponsed.
+ * \note Free is postponsed if the coord is dirty or it has children
+ *	or members postponsed for free.
  */
 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) {
     coord_t *parent;
     coord_t *child;
     geo_t *member;
-    int r;
+    int cm_cnt;			/* children & members counter */
 
     parent = coord->parent;
     if(parent == NULL)
 	return ERR;
 
-    if(rdman_is_dirty(rdman)) {
-	if(coord->flags & COF_FREE)
+    cm_cnt = 0;
+    FORCHILDREN(coord, child) {
+	cm_cnt++;
+	if(!(child->flags & COF_FREE))
 	    return ERR;
-
-	FORCHILDREN(coord, child) {
-	    if(!(child->flags & COF_FREE))
-		return ERR;
-	}
-	FORMEMBERS(coord, member) {
-	    if(!(member->flags & GEF_FREE))
-		return ERR;
-	}
-	coord->flags |= COF_FREE;
-	coord_hide(coord);
-	if(!(coord->flags & COF_DIRTY)) {
-	    r = add_dirty_coord(rdman, coord);
-	    if(r != OK)
-		return ERR;
-	}
-	r = add_free_obj(rdman, coord, (free_func_t)rdman_coord_free);
-	if(r != OK)
+    }
+    FORMEMBERS(coord, member) {
+	cm_cnt++;
+	if(!(member->flags & GEF_FREE))
 	    return ERR;
-	return OK;
     }
-
-    if(FIRST_MEMBER(coord) != NULL)
-	return ERR;
-
-    if(FIRST_CHILD(coord) != NULL)
-	return ERR;
+    
+    if(cm_cnt || rdman_is_dirty(rdman))
+	return rdman_coord_free_postponse(rdman, coord);
 
     /* Free canvas (\ref redraw) */
     if(coord->flags & COF_OWN_CANVAS)
 	free_canvas(coord->canvas);
 
     RM_CHILD(parent, coord);
-    subject_free(&rdman->ob_factory, coord->mouse_event);
+    subject_free(coord->mouse_event);
     elmpool_elm_free(rdman->coord_pool, coord);
     rdman->n_coords--;
 
@@ -1118,7 +1124,6 @@
     int n_dirty_areas;
     area_t **dirty_areas;
     event_t event;
-    ob_factory_t *factory;
     subject_t *redraw;
 
     r = clean_rdman_dirties(rdman);
@@ -1142,11 +1147,10 @@
     /* Free postponsed removing */
     free_free_objs(rdman);
 
-    factory = rdman_get_ob_factory(rdman);
     redraw = rdman_get_redraw_subject(rdman);
     event.type = EVT_RDMAN_REDRAW;
     event.tgt = event.cur_tgt = redraw;
-    subject_notify(factory, redraw, &event);
+    subject_notify(redraw, &event);
 
     return OK;
 }