Mercurial > MadButterfly
annotate src/observer.c @ 149:52f7566777f9
-
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Thu, 25 Sep 2008 11:29:42 +0800 |
parents | d2cc7400c971 |
children | c7e5b8779bb5 |
rev | line source |
---|---|
73 | 1 #include <stdio.h> |
2 #include "redraw_man.h" | |
3 #include "observer.h" | |
4 #include "tools.h" | |
5 | |
126 | 6 #ifndef ASSERT |
7 #define ASSERT(x) | |
8 #endif | |
9 | |
73 | 10 subject_t *subject_new(ob_factory_t *factory, void *obj, int obj_type) { |
11 subject_t *subject; | |
12 | |
13 subject = factory->subject_alloc(factory); | |
14 if(subject == NULL) | |
15 return NULL; | |
16 | |
17 subject->obj = obj; | |
18 subject->obj_type = obj_type; | |
19 subject->flags = 0; | |
20 STAILQ_INIT(subject->observers); | |
21 | |
22 return subject; | |
23 } | |
24 | |
125
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
25 /*! |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
26 * \todo Keep ob_factory following subject objects. |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
27 */ |
73 | 28 void subject_free(ob_factory_t *factory, subject_t *subject) { |
29 observer_t *observer; | |
30 | |
126 | 31 ASSERT(!(subject->flags & SUBF_FREE)); |
125
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
32 if(subject->flags & SUBF_BUSY) { |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
33 /* Postpond the request until busy status been stoped. |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
34 * SUBF_BUSY means in subject_notify(). |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
35 */ |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
36 subject->flags |= SUBF_FREE; |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
37 return; |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
38 } |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
39 |
73 | 40 while((observer = STAILQ_HEAD(subject->observers))) { |
41 STAILQ_REMOVE(subject->observers, observer_t, next, observer); | |
42 factory->observer_free(factory, observer); | |
43 } | |
44 factory->subject_free(factory, subject); | |
45 } | |
46 | |
47 | |
48 void subject_notify(ob_factory_t *factory, subject_t *subject, event_t *evt) { | |
49 observer_t *observer; | |
50 | |
77 | 51 evt->tgt = subject; |
73 | 52 while(subject) { |
127
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
53 /*! |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
54 * \note What is happend when the subject is freed by observer? |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
55 * Postponding the request of free until notification |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
56 * been finished. (\ref SUBF_BUSY / \ref SUBF_FREE) |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
57 */ |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
58 subject->flags |= SUBF_BUSY; |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
59 |
77 | 60 evt->cur_tgt = subject->obj; |
73 | 61 for(observer = STAILQ_HEAD(subject->observers); |
62 observer != NULL; | |
63 observer = STAILQ_NEXT(observer_t, next, observer)) { | |
64 observer->hdr(evt, observer->arg); | |
65 } | |
66 | |
127
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
67 subject->flags &= ~SUBF_BUSY; |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
68 if(subject->flags & SUBF_FREE) |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
69 subject_free(factory, subject); |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
70 |
73 | 71 if(subject->flags & SUBF_STOP_PROPAGATE) |
72 break; | |
73 | |
74 subject = factory->get_parent_subject(factory, subject); | |
75 } | |
125
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
76 |
73 | 77 } |
78 | |
79 observer_t *subject_add_observer(ob_factory_t *factory, | |
80 subject_t *subject, | |
81 evt_handler hdr, void *arg) { | |
82 observer_t *observer; | |
83 | |
84 observer = factory->observer_alloc(factory); | |
85 if(observer == NULL) | |
86 return NULL; | |
87 observer->hdr = hdr; | |
88 observer->arg = arg; | |
89 | |
90 STAILQ_INS_TAIL(subject->observers, observer_t, next, observer); | |
91 | |
92 return observer; | |
93 } | |
94 | |
95 void subject_remove_observer(ob_factory_t *factory, | |
96 subject_t *subject, | |
97 observer_t *observer) { | |
98 STAILQ_REMOVE(subject->observers, observer_t, next, observer); | |
99 factory->observer_free(factory, observer); | |
100 } | |
101 | |
102 #ifdef UNITTEST | |
103 | |
104 #include <CUnit/Basic.h> | |
105 #include <stdlib.h> | |
106 | |
107 static subject_t *test_subject_alloc(ob_factory_t *factory) { | |
108 subject_t *subject; | |
109 | |
110 subject = (subject_t *)malloc(sizeof(subject_t)); | |
111 return subject; | |
112 } | |
113 | |
114 static void test_subject_free(ob_factory_t *factory, subject_t *subject) { | |
115 free(subject); | |
116 } | |
117 | |
118 static observer_t *test_observer_alloc(ob_factory_t *factory) { | |
119 observer_t *observer; | |
120 | |
121 observer = (observer_t *)malloc(sizeof(observer_t)); | |
122 return observer; | |
123 } | |
124 | |
125 static void test_observer_free(ob_factory_t *factory, observer_t *observer) { | |
126 free(observer); | |
127 } | |
128 | |
129 static subject_t *test_get_parent_subject(ob_factory_t *factory, | |
130 subject_t *subject) { | |
131 return NULL; | |
132 } | |
133 | |
134 static ob_factory_t test_factory = { | |
135 test_subject_alloc, | |
136 test_subject_free, | |
137 test_observer_alloc, | |
138 test_observer_free, | |
139 test_get_parent_subject | |
140 }; | |
141 | |
142 static void handler(event_t *evt, void *arg) { | |
143 int *cnt = (int *)arg; | |
144 | |
74 | 145 CU_ASSERT(evt->type == EVT_MOUSE_OUT); |
73 | 146 (*cnt)++; |
147 } | |
148 | |
149 void test_observer(void) { | |
150 subject_t *subject; | |
74 | 151 observer_t *observer[2]; |
73 | 152 event_t evt; |
153 int cnt = 0; | |
154 | |
155 subject = subject_new(&test_factory, NULL, 0); | |
156 subject->flags |= SUBF_STOP_PROPAGATE; | |
74 | 157 observer[0] = subject_add_observer(&test_factory, subject, |
158 handler, &cnt); | |
159 observer[1] = subject_add_observer(&test_factory, subject, | |
160 handler, &cnt); | |
73 | 161 |
74 | 162 evt.type = EVT_MOUSE_OUT; |
73 | 163 evt.tgt = NULL; |
164 evt.cur_tgt = NULL; | |
165 subject_notify(&test_factory, subject, &evt); | |
74 | 166 CU_ASSERT(cnt == 2); |
73 | 167 |
74 | 168 subject_remove_observer(&test_factory, subject, observer[0]); |
169 subject_remove_observer(&test_factory, subject, observer[1]); | |
73 | 170 subject_free(&test_factory, subject); |
171 } | |
172 | |
173 CU_pSuite get_observer_suite(void) { | |
174 CU_pSuite suite; | |
175 | |
176 suite = CU_add_suite("Suite_observer", NULL, NULL); | |
177 CU_ADD_TEST(suite, test_observer); | |
178 | |
179 return suite; | |
180 } | |
181 | |
182 #endif /* UNITTEST */ |