Mercurial > MadButterfly
annotate src/observer.c @ 221:ad4f8a956505
Implement a workaround for the button class. However, this won't solve all issues. We can use this as example to fix the mouse out event issue. When we move the curosr over the text inside the button. The upper layer group will receive MOUSE_OUT events. This is absolute incorrect.
author | wycc |
---|---|
date | Sun, 14 Dec 2008 12:35:13 +0800 |
parents | 748896358da2 |
children | 29e1b2bffe4c |
rev | line source |
---|---|
73 | 1 #include <stdio.h> |
186
530bb7728546
Move header files to $(top_srcdir)/include/ and prefixed with 'mb_'.
Thinker K.F. Li <thinker@branda.to>
parents:
185
diff
changeset
|
2 #include "mb_redraw_man.h" |
530bb7728546
Move header files to $(top_srcdir)/include/ and prefixed with 'mb_'.
Thinker K.F. Li <thinker@branda.to>
parents:
185
diff
changeset
|
3 #include "mb_observer.h" |
530bb7728546
Move header files to $(top_srcdir)/include/ and prefixed with 'mb_'.
Thinker K.F. Li <thinker@branda.to>
parents:
185
diff
changeset
|
4 #include "mb_tools.h" |
73 | 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 | |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
22 subject->factory = factory; |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
23 |
73 | 24 return subject; |
25 } | |
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 /*! |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
28 * \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
|
29 */ |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
30 void subject_free(subject_t *subject) { |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
31 ob_factory_t *factory = subject->factory; |
73 | 32 observer_t *observer; |
33 | |
126 | 34 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
|
35 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
|
36 /* 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
|
37 * 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
|
38 */ |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
39 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
|
40 return; |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
41 } |
1c1f28c124c9
Postponding free request when a subject is in subject_notify
Thinker K.F. Li <thinker@branda.to>
parents:
77
diff
changeset
|
42 |
73 | 43 while((observer = STAILQ_HEAD(subject->observers))) { |
44 STAILQ_REMOVE(subject->observers, observer_t, next, observer); | |
45 factory->observer_free(factory, observer); | |
46 } | |
47 factory->subject_free(factory, subject); | |
48 } | |
49 | |
50 | |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
51 void subject_notify(subject_t *subject, event_t *evt) { |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
52 ob_factory_t *factory = subject->factory; |
73 | 53 observer_t *observer; |
194
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
54 subject_t *old_subject; |
73 | 55 |
77 | 56 evt->tgt = subject; |
73 | 57 while(subject) { |
127
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
58 /*! |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
59 * \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
|
60 * 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
|
61 * 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
|
62 */ |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
63 subject->flags |= SUBF_BUSY; |
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
64 |
77 | 65 evt->cur_tgt = subject->obj; |
73 | 66 for(observer = STAILQ_HEAD(subject->observers); |
67 observer != NULL; | |
68 observer = STAILQ_NEXT(observer_t, next, observer)) { | |
198
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
69 if (observer->type == EVT_ANY || observer->type == evt->type) |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
70 observer->hdr(evt, observer->arg); |
73 | 71 } |
72 | |
127
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
73 subject->flags &= ~SUBF_BUSY; |
194
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
74 |
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
75 old_subject = subject; |
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
76 subject = factory->get_parent_subject(factory, subject); |
127
d2cc7400c971
Bug of subject_notify() when free subjects.
Thinker K.F. Li <thinker@branda.to>
parents:
126
diff
changeset
|
77 |
194
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
78 if(old_subject->flags & SUBF_FREE) |
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
79 subject_free(old_subject); |
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
80 |
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
81 if(old_subject->flags & SUBF_STOP_PROPAGATE) |
73 | 82 break; |
83 } | |
84 } | |
85 | |
206
748896358da2
Export subject_add_event_observer() to rest of the system.
Thinker K.F. Li <thinker@branda.to>
parents:
202
diff
changeset
|
86 /*! \brief Add an observer for any type of events. |
748896358da2
Export subject_add_event_observer() to rest of the system.
Thinker K.F. Li <thinker@branda.to>
parents:
202
diff
changeset
|
87 */ |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
88 observer_t *subject_add_observer(subject_t *subject, |
73 | 89 evt_handler hdr, void *arg) { |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
90 ob_factory_t *factory = subject->factory; |
73 | 91 observer_t *observer; |
92 | |
93 observer = factory->observer_alloc(factory); | |
94 if(observer == NULL) | |
95 return NULL; | |
96 observer->hdr = hdr; | |
97 observer->arg = arg; | |
198
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
98 observer->type = EVT_ANY; |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
99 |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
100 STAILQ_INS_TAIL(subject->observers, observer_t, next, observer); |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
101 |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
102 return observer; |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
103 } |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
104 |
206
748896358da2
Export subject_add_event_observer() to rest of the system.
Thinker K.F. Li <thinker@branda.to>
parents:
202
diff
changeset
|
105 /*! \brief Add an observer for specified type of events. |
748896358da2
Export subject_add_event_observer() to rest of the system.
Thinker K.F. Li <thinker@branda.to>
parents:
202
diff
changeset
|
106 */ |
198
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
107 observer_t *subject_add_event_observer(subject_t *subject, int type, |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
108 evt_handler hdr, void *arg) { |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
109 ob_factory_t *factory = subject->factory; |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
110 observer_t *observer; |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
111 |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
112 observer = factory->observer_alloc(factory); |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
113 if(observer == NULL) |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
114 return NULL; |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
115 observer->hdr = hdr; |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
116 observer->arg = arg; |
f9d507a3e1d9
Add event observer which listen to one event type only.
wycc@wycc-desktop
parents:
192
diff
changeset
|
117 observer->type = type; |
73 | 118 |
119 STAILQ_INS_TAIL(subject->observers, observer_t, next, observer); | |
120 | |
121 return observer; | |
122 } | |
123 | |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
124 void subject_remove_observer(subject_t *subject, |
73 | 125 observer_t *observer) { |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
126 ob_factory_t *factory = subject->factory; |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
127 |
73 | 128 STAILQ_REMOVE(subject->observers, observer_t, next, observer); |
129 factory->observer_free(factory, observer); | |
130 } | |
131 | |
132 #ifdef UNITTEST | |
133 | |
134 #include <CUnit/Basic.h> | |
135 #include <stdlib.h> | |
136 | |
137 static subject_t *test_subject_alloc(ob_factory_t *factory) { | |
138 subject_t *subject; | |
139 | |
140 subject = (subject_t *)malloc(sizeof(subject_t)); | |
141 return subject; | |
142 } | |
143 | |
144 static void test_subject_free(ob_factory_t *factory, subject_t *subject) { | |
145 free(subject); | |
146 } | |
147 | |
148 static observer_t *test_observer_alloc(ob_factory_t *factory) { | |
149 observer_t *observer; | |
150 | |
151 observer = (observer_t *)malloc(sizeof(observer_t)); | |
152 return observer; | |
153 } | |
154 | |
155 static void test_observer_free(ob_factory_t *factory, observer_t *observer) { | |
156 free(observer); | |
157 } | |
158 | |
159 static subject_t *test_get_parent_subject(ob_factory_t *factory, | |
160 subject_t *subject) { | |
161 return NULL; | |
162 } | |
163 | |
164 static ob_factory_t test_factory = { | |
165 test_subject_alloc, | |
166 test_subject_free, | |
167 test_observer_alloc, | |
168 test_observer_free, | |
169 test_get_parent_subject | |
170 }; | |
171 | |
172 static void handler(event_t *evt, void *arg) { | |
173 int *cnt = (int *)arg; | |
174 | |
74 | 175 CU_ASSERT(evt->type == EVT_MOUSE_OUT); |
73 | 176 (*cnt)++; |
177 } | |
178 | |
179 void test_observer(void) { | |
180 subject_t *subject; | |
74 | 181 observer_t *observer[2]; |
73 | 182 event_t evt; |
183 int cnt = 0; | |
184 | |
185 subject = subject_new(&test_factory, NULL, 0); | |
186 subject->flags |= SUBF_STOP_PROPAGATE; | |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
187 observer[0] = subject_add_observer(subject, handler, &cnt); |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
188 observer[1] = subject_add_observer(subject, handler, &cnt); |
73 | 189 |
74 | 190 evt.type = EVT_MOUSE_OUT; |
73 | 191 evt.tgt = NULL; |
192 evt.cur_tgt = NULL; | |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
193 subject_notify(subject, &evt); |
74 | 194 CU_ASSERT(cnt == 2); |
73 | 195 |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
196 subject_remove_observer(subject, observer[0]); |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
197 subject_remove_observer(subject, observer[1]); |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
198 subject_free(subject); |
73 | 199 } |
200 | |
201 CU_pSuite get_observer_suite(void) { | |
202 CU_pSuite suite; | |
203 | |
204 suite = CU_add_suite("Suite_observer", NULL, NULL); | |
205 CU_ADD_TEST(suite, test_observer); | |
206 | |
207 return suite; | |
208 } | |
209 | |
210 #endif /* UNITTEST */ |