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