Mercurial > MadButterfly
annotate src/X_supp.c @ 101:d6f9af55b0d0
More documentation.
1. main page
2. copyright
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Wed, 10 Sep 2008 13:35:56 +0800 |
parents | 42698de1f653 |
children | 5df7403b6fbc |
rev | line source |
---|---|
77 | 1 #include <stdio.h> |
78 | 2 #include <stdlib.h> |
3 #include <string.h> | |
77 | 4 #include <X11/Xlib.h> |
5 #include <X11/Xutil.h> | |
78 | 6 #include <cairo.h> |
7 #include <cairo-xlib.h> | |
77 | 8 #include "redraw_man.h" |
9 #include "mb_timer.h" | |
78 | 10 #include "X_supp.h" |
77 | 11 |
12 | |
78 | 13 static unsigned int get_button_state(unsigned int state) { |
14 unsigned int but = 0; | |
15 | |
16 if(state & Button1Mask) | |
17 but |= MOUSE_BUT1; | |
18 if(state & Button2Mask) | |
19 but |= MOUSE_BUT2; | |
20 if(state & Button3Mask) | |
21 but |= MOUSE_BUT3; | |
22 | |
23 return but; | |
24 } | |
25 | |
26 static unsigned int get_button(unsigned int button) { | |
27 switch(button) { | |
28 case Button1: | |
29 return MOUSE_BUT1; | |
30 case Button2: | |
31 return MOUSE_BUT2; | |
32 case Button3: | |
33 return MOUSE_BUT3; | |
34 } | |
35 return 0; | |
36 } | |
37 | |
38 /*! \brief Notify observers of the shape at specified | |
39 * position for mouse event. | |
40 * | |
41 * Observers of parent shapes may be called if the subject is not | |
42 * with SUBF_STOP_PROPAGATE flag. The subject of mouse event | |
43 * for a shape is returned by sh_get_mouse_event_subject(). | |
44 */ | |
45 static void notify_shapes(redraw_man_t *rdman, | |
84
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
46 shape_t *shape, |
78 | 47 co_aix x, co_aix y, int etype, |
48 unsigned int state, | |
49 unsigned int button) { | |
50 mouse_event_t mouse_event; | |
51 subject_t *subject; | |
52 ob_factory_t *factory; | |
53 | |
54 mouse_event.event.type = etype; | |
55 mouse_event.x = x; | |
56 mouse_event.y = y; | |
57 mouse_event.but_state = state; | |
58 mouse_event.button = button; | |
59 | |
60 subject = sh_get_mouse_event_subject(shape); | |
61 factory = rdman_get_ob_factory(rdman); | |
62 | |
63 subject_notify(factory, subject, (event_t *)&mouse_event); | |
64 } | |
65 | |
66 /*! \brief Dispatch all X events in the queue. | |
77 | 67 */ |
83 | 68 static void handle_x_event(X_MB_runtime_t *rt) { |
69 Display *display = rt->display; | |
70 redraw_man_t *rdman = rt->rdman; | |
77 | 71 XEvent evt; |
72 XMotionEvent *mevt; | |
78 | 73 XButtonEvent *bevt; |
81 | 74 XExposeEvent *eevt; |
75 co_aix x, y, w, h; | |
76 | |
77 int eflag = 0; | |
82 | 78 int ex1=0, ey1=0, ex2=0, ey2=0; |
81 | 79 |
84
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
80 shape_t *shape; |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
81 |
78 | 82 unsigned int state, button; |
84
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
83 int in_stroke; |
77 | 84 int r; |
85 | |
86 while(XEventsQueued(display, QueuedAfterReading) > 0) { | |
87 r = XNextEvent(display, &evt); | |
88 if(r == -1) | |
89 break; | |
90 | |
91 switch(evt.type) { | |
78 | 92 case ButtonPress: |
93 bevt = (XButtonEvent *)&evt; | |
94 x = bevt->x; | |
95 y = bevt->y; | |
96 state = get_button_state(bevt->state); | |
97 button = get_button(bevt->button); | |
98 | |
84
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
99 shape = find_shape_at_pos(rdman, x, y, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
100 &in_stroke); |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
101 if(shape) |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
102 notify_shapes(rdman, shape, x, y, EVT_MOUSE_BUT_PRESS, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
103 state, button); |
78 | 104 break; |
105 | |
106 case ButtonRelease: | |
107 bevt = (XButtonEvent *)&evt; | |
108 x = bevt->x; | |
109 y = bevt->y; | |
110 state = get_button_state(bevt->state); | |
111 button = get_button(bevt->button); | |
112 | |
84
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
113 shape = find_shape_at_pos(rdman, x, y, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
114 &in_stroke); |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
115 if(shape) |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
116 notify_shapes(rdman, shape, x, y, EVT_MOUSE_BUT_RELEASE, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
117 state, button); |
78 | 118 break; |
119 | |
77 | 120 case MotionNotify: |
121 mevt = (XMotionEvent *)&evt; | |
122 x = mevt->x; | |
123 y = mevt->y; | |
78 | 124 state = get_button_state(mevt->state); |
77 | 125 |
84
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
126 shape = find_shape_at_pos(rdman, x, y, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
127 &in_stroke); |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
128 if(shape != NULL) { |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
129 if(rt->last != shape) { |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
130 if(rt->last) |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
131 notify_shapes(rdman, rt->last, x, y, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
132 EVT_MOUSE_OUT, state, 0); |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
133 notify_shapes(rdman, shape, x, y, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
134 EVT_MOUSE_OVER, state, 0); |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
135 rt->last = shape; |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
136 } else |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
137 notify_shapes(rdman, shape, x, y, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
138 EVT_MOUSE_MOVE, state, 0); |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
139 } else { |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
140 if(rt->last) { |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
141 notify_shapes(rdman, rt->last, x, y, |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
142 EVT_MOUSE_OUT, state, 0); |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
143 rt->last = NULL; |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
144 } |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
145 } |
77 | 146 break; |
147 | |
148 case Expose: | |
81 | 149 eevt = &evt.xexpose; |
150 x = eevt->x; | |
151 y = eevt->y; | |
152 w = eevt->width; | |
153 h = eevt->height; | |
154 | |
155 if(eflag) { | |
156 if(x < ex1) | |
157 ex1 = x; | |
158 if(y < ey1) | |
159 ey1 = y; | |
160 if((x + w) > ex2) | |
161 ex2 = x + w; | |
162 if((y + h) > ey2) | |
163 ey2 = y + h; | |
164 } else { | |
165 ex1 = x; | |
166 ey1 = y; | |
167 ex2 = x + w; | |
168 ey2 = y + h; | |
169 eflag = 1; | |
170 } | |
77 | 171 break; |
172 } | |
173 } | |
81 | 174 if(eflag) { |
175 rdman_redraw_area(rdman, ex1, ey1, (ex2 - ex1), (ey2 - ey1)); | |
176 eflag = 0; | |
177 } | |
77 | 178 XFlush(display); |
179 } | |
180 | |
181 /*! \brief Handle connection coming data and timeout of timers. | |
78 | 182 * |
183 * \param display is a Display returned by XOpenDisplay(). | |
184 * \param rdman is a redraw manager. | |
185 * \param tman is a timer manager. | |
186 * | |
187 * The display is managed by specified rdman and tman. rdman draws | |
188 * on the display, and tman trigger actions according timers. | |
77 | 189 */ |
83 | 190 void X_MB_handle_connection(X_MB_runtime_t *rt) { |
191 Display *display = rt->display; | |
192 redraw_man_t *rdman = rt->rdman; | |
193 mb_tman_t *tman = rt->tman; | |
77 | 194 int fd; |
195 mb_timeval_t now, tmo; | |
196 struct timeval tv; | |
197 fd_set rfds; | |
198 int nfds; | |
199 int r; | |
200 | |
78 | 201 rdman_redraw_all(rdman); |
202 XFlush(display); | |
203 | |
77 | 204 fd = XConnectionNumber(display); |
205 nfds = fd + 1; | |
206 while(1) { | |
207 FD_ZERO(&rfds); | |
208 FD_SET(fd, &rfds); | |
209 | |
210 get_now(&now); | |
211 r = mb_tman_next_timeout(tman, &now, &tmo); | |
212 | |
213 if(r == 0) { | |
214 tv.tv_sec = MB_TIMEVAL_SEC(&tmo); | |
215 tv.tv_usec = MB_TIMEVAL_USEC(&tmo); | |
216 r = select(nfds, &rfds, NULL, NULL, &tv); | |
217 } else | |
218 r = select(nfds, &rfds, NULL, NULL, NULL); | |
219 | |
220 if(r == -1) { | |
221 perror("select"); | |
222 break; | |
223 } | |
224 | |
225 if(r == 0) { | |
226 get_now(&now); | |
227 mb_tman_handle_timeout(tman, &now); | |
228 rdman_redraw_changed(rdman); | |
229 XFlush(display); | |
230 } else if(FD_ISSET(fd, &rfds)){ | |
83 | 231 handle_x_event(rt); |
77 | 232 } |
233 } | |
234 } | |
78 | 235 |
236 #define ERR -1 | |
237 #define OK 0 | |
238 | |
239 static int X_init_connection(const char *display_name, | |
240 int w, int h, | |
241 Display **displayp, | |
242 Visual **visualp, | |
243 Window *winp) { | |
244 Display *display; | |
245 Window root, win; | |
246 Visual *visual; | |
247 int screen; | |
248 XSetWindowAttributes wattr; | |
249 int depth; | |
250 int x, y; | |
251 int r; | |
252 | |
253 display = XOpenDisplay(display_name); | |
254 if(display == NULL) | |
255 return ERR; | |
256 | |
257 screen = DefaultScreen(display); | |
258 root = DefaultRootWindow(display); | |
259 visual = DefaultVisual(display, screen); | |
260 depth = DefaultDepth(display, screen); | |
261 wattr.override_redirect = False; | |
262 x = 10; | |
263 y = 10; | |
264 win = XCreateWindow(display, root, | |
265 x, y, | |
266 w, h, | |
267 1, depth, InputOutput, visual, | |
268 CWOverrideRedirect, &wattr); | |
269 r = XMapWindow(display, win); | |
270 if(r == -1) { | |
271 XCloseDisplay(display); | |
272 return ERR; | |
273 } | |
274 | |
84
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
275 XSelectInput(display, win, PointerMotionMask | ExposureMask | |
42698de1f653
Support translate() function for transform attribute of 'g' tag.
Thinker K.F. Li <thinker@branda.to>
parents:
83
diff
changeset
|
276 ButtonPressMask | ButtonReleaseMask); |
78 | 277 XFlush(display); |
278 | |
279 *displayp = display; | |
280 *visualp = visual; | |
281 *winp = win; | |
282 | |
283 return OK; | |
284 } | |
285 | |
286 /*! \brief Initialize a MadButterfy runtime for Xlib. | |
287 * | |
288 * It setups a runtime environment to run MadButterfly with Xlib. | |
289 * Users should specify width and height of the opening window. | |
290 */ | |
291 int X_MB_init(const char *display_name, | |
292 int w, int h, X_MB_runtime_t *xmb_rt) { | |
293 memset(xmb_rt, 0, sizeof(X_MB_runtime_t)); | |
294 | |
295 xmb_rt->w = w; | |
296 xmb_rt->h = h; | |
297 X_init_connection(display_name, w, h, &xmb_rt->display, | |
298 &xmb_rt->visual, &xmb_rt->win); | |
299 | |
300 xmb_rt->surface = | |
301 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); | |
302 | |
303 xmb_rt->backend_surface = | |
304 cairo_xlib_surface_create(xmb_rt->display, | |
305 xmb_rt->win, | |
306 xmb_rt->visual, | |
307 w, h); | |
308 | |
309 xmb_rt->cr = cairo_create(xmb_rt->surface); | |
310 xmb_rt->backend_cr = cairo_create(xmb_rt->backend_surface); | |
311 | |
312 cairo_set_source_surface(xmb_rt->backend_cr, xmb_rt->surface, 0, 0); | |
313 | |
314 xmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t)); | |
315 redraw_man_init(xmb_rt->rdman, xmb_rt->cr, xmb_rt->backend_cr); | |
316 | |
317 xmb_rt->tman = mb_tman_new(); | |
318 | |
83 | 319 xmb_rt->last = NULL; |
320 | |
78 | 321 return OK; |
322 } | |
323 | |
324 void X_MB_destroy(X_MB_runtime_t *xmb_rt) { | |
325 if(xmb_rt->rdman) { | |
326 redraw_man_destroy(xmb_rt->rdman); | |
327 free(xmb_rt->rdman); | |
328 } | |
329 | |
330 if(xmb_rt->tman) | |
331 mb_tman_free(xmb_rt->tman); | |
332 | |
333 if(xmb_rt->cr) | |
334 cairo_destroy(xmb_rt->cr); | |
335 if(xmb_rt->backend_cr) | |
336 cairo_destroy(xmb_rt->backend_cr); | |
337 | |
338 if(xmb_rt->surface) | |
339 cairo_surface_destroy(xmb_rt->surface); | |
340 if(xmb_rt->backend_surface) | |
341 cairo_surface_destroy(xmb_rt->backend_surface); | |
342 | |
343 if(xmb_rt->display) | |
344 XCloseDisplay(xmb_rt->display); | |
345 } | |
346 |