Mercurial > MadButterfly
view src/observer.c @ 131:6a8588df68af
Tank can change direction and navigate on the mud area
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Wed, 17 Sep 2008 01:30:25 +0800 |
parents | d2cc7400c971 |
children | c7e5b8779bb5 |
line wrap: on
line source
#include <stdio.h> #include "redraw_man.h" #include "observer.h" #include "tools.h" #ifndef ASSERT #define ASSERT(x) #endif subject_t *subject_new(ob_factory_t *factory, void *obj, int obj_type) { subject_t *subject; subject = factory->subject_alloc(factory); if(subject == NULL) return NULL; subject->obj = obj; subject->obj_type = obj_type; subject->flags = 0; STAILQ_INIT(subject->observers); return subject; } /*! * \todo Keep ob_factory following subject objects. */ void subject_free(ob_factory_t *factory, subject_t *subject) { observer_t *observer; ASSERT(!(subject->flags & SUBF_FREE)); if(subject->flags & SUBF_BUSY) { /* Postpond the request until busy status been stoped. * SUBF_BUSY means in subject_notify(). */ subject->flags |= SUBF_FREE; return; } while((observer = STAILQ_HEAD(subject->observers))) { STAILQ_REMOVE(subject->observers, observer_t, next, observer); factory->observer_free(factory, observer); } factory->subject_free(factory, subject); } void subject_notify(ob_factory_t *factory, subject_t *subject, event_t *evt) { observer_t *observer; evt->tgt = subject; while(subject) { /*! * \note What is happend when the subject is freed by observer? * Postponding the request of free until notification * been finished. (\ref SUBF_BUSY / \ref SUBF_FREE) */ subject->flags |= SUBF_BUSY; evt->cur_tgt = subject->obj; for(observer = STAILQ_HEAD(subject->observers); observer != NULL; observer = STAILQ_NEXT(observer_t, next, observer)) { observer->hdr(evt, observer->arg); } subject->flags &= ~SUBF_BUSY; if(subject->flags & SUBF_FREE) subject_free(factory, subject); if(subject->flags & SUBF_STOP_PROPAGATE) break; subject = factory->get_parent_subject(factory, subject); } } observer_t *subject_add_observer(ob_factory_t *factory, subject_t *subject, evt_handler hdr, void *arg) { observer_t *observer; observer = factory->observer_alloc(factory); if(observer == NULL) return NULL; observer->hdr = hdr; observer->arg = arg; STAILQ_INS_TAIL(subject->observers, observer_t, next, observer); return observer; } void subject_remove_observer(ob_factory_t *factory, subject_t *subject, observer_t *observer) { STAILQ_REMOVE(subject->observers, observer_t, next, observer); factory->observer_free(factory, observer); } #ifdef UNITTEST #include <CUnit/Basic.h> #include <stdlib.h> static subject_t *test_subject_alloc(ob_factory_t *factory) { subject_t *subject; subject = (subject_t *)malloc(sizeof(subject_t)); return subject; } static void test_subject_free(ob_factory_t *factory, subject_t *subject) { free(subject); } static observer_t *test_observer_alloc(ob_factory_t *factory) { observer_t *observer; observer = (observer_t *)malloc(sizeof(observer_t)); return observer; } static void test_observer_free(ob_factory_t *factory, observer_t *observer) { free(observer); } static subject_t *test_get_parent_subject(ob_factory_t *factory, subject_t *subject) { return NULL; } static ob_factory_t test_factory = { test_subject_alloc, test_subject_free, test_observer_alloc, test_observer_free, test_get_parent_subject }; static void handler(event_t *evt, void *arg) { int *cnt = (int *)arg; CU_ASSERT(evt->type == EVT_MOUSE_OUT); (*cnt)++; } void test_observer(void) { subject_t *subject; observer_t *observer[2]; event_t evt; int cnt = 0; 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); evt.type = EVT_MOUSE_OUT; evt.tgt = NULL; evt.cur_tgt = NULL; subject_notify(&test_factory, 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); } CU_pSuite get_observer_suite(void) { CU_pSuite suite; suite = CU_add_suite("Suite_observer", NULL, NULL); CU_ADD_TEST(suite, test_observer); return suite; } #endif /* UNITTEST */