Mercurial > MadButterfly
comparison src/X_supp.c @ 1067:7b4e80ab671a openvg
merge from default branch
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Wed, 01 Dec 2010 12:25:56 +0800 |
parents | bd18951b51d5 e415c55b4a0d |
children | d09f603438d8 |
comparison
equal
deleted
inserted
replaced
630:bd18951b51d5 | 1067:7b4e80ab671a |
---|---|
1 // -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 4; -*- | |
2 // vim: sw=4:ts=8:sts=4 | |
1 #include <stdio.h> | 3 #include <stdio.h> |
2 #include <stdlib.h> | 4 #include <stdlib.h> |
3 #include <string.h> | 5 #include <string.h> |
4 #include <X11/Xlib.h> | 6 #include <X11/Xlib.h> |
5 #include <X11/Xutil.h> | 7 #include <X11/Xutil.h> |
8 #include <cairo-xlib.h> | |
6 #include "mb_graph_engine.h" | 9 #include "mb_graph_engine.h" |
7 #include "mb_redraw_man.h" | 10 #include "mb_redraw_man.h" |
8 #include "mb_timer.h" | 11 #include "mb_timer.h" |
9 #include "mb_X_supp.h" | 12 #include "mb_X_supp.h" |
13 #include "mb_backend.h" | |
14 #include "mb_backend_utils.h" | |
15 #include "config.h" | |
16 | |
17 #ifdef XSHM | |
18 /* \sa http://www.xfree86.org/current/mit-shm.html */ | |
19 #include <sys/ipc.h> | |
20 #include <sys/shm.h> | |
21 #include <X11/extensions/XShm.h> | |
22 static void XSHM_update(X_supp_runtime_t *xmb_rt); | |
23 #endif | |
10 | 24 |
11 #define ERR -1 | 25 #define ERR -1 |
12 #define OK 0 | 26 #define OK 0 |
13 | 27 |
28 #define ASSERT(x) | |
29 | |
14 #define ONLY_MOUSE_MOVE_RAW 1 | 30 #define ONLY_MOUSE_MOVE_RAW 1 |
31 | |
32 static mb_timer_factory_t *_timer_factory = &tman_timer_factory; | |
15 | 33 |
16 /*! \ingroup xkb | 34 /*! \ingroup xkb |
17 * @{ | 35 * @{ |
18 */ | 36 */ |
19 struct _X_kb_info { | 37 struct _X_kb_info { |
20 int keycode_min, keycode_max; | 38 int keycode_min, keycode_max; |
21 int ksym_per_code; | 39 int ksym_per_code; |
22 KeySym *syms; | 40 KeySym *syms; |
23 subject_t *kbevents; | 41 subject_t *kbevents; |
24 ob_factory_t *ob_factory; | 42 observer_factory_t *observer_factory; |
25 }; | 43 }; |
26 | 44 |
27 /* @} */ | 45 /* @} */ |
28 #define MAX_MONITORS 200 | 46 |
29 typedef struct { | 47 struct _X_supp_runtime { |
30 int type; | |
31 int fd; | |
32 mb_eventcb_t f; | |
33 void *arg; | |
34 } monitor_t; | |
35 struct _X_MB_runtime { | |
36 Display *display; | 48 Display *display; |
37 Window win; | 49 Window win; |
38 Visual *visual; | 50 Visual *visual; |
39 mbe_surface_t *surface, *backend_surface; | 51 mbe_surface_t *surface, *backend_surface; |
40 mbe_pattern_t *surface_ptn; | 52 mbe_pattern_t *surface_ptn; |
41 mbe_t *cr, *backend_cr; | 53 mbe_t *cr, *backend_cr; |
42 redraw_man_t *rdman; | 54 redraw_man_t *rdman; |
43 mb_tman_t *tman; | |
44 mb_img_ldr_t *img_ldr; | 55 mb_img_ldr_t *img_ldr; |
45 int w, h; | 56 int w, h; |
46 | 57 |
47 X_kb_info_t kbinfo; | 58 X_kb_info_t kbinfo; |
48 monitor_t monitors[MAX_MONITORS]; | 59 mb_IO_man_t *io_man; |
49 int n_monitor; | 60 mb_timer_man_t *timer_man; |
50 | 61 |
51 #ifndef ONLY_MOUSE_MOVE_RAW | 62 #ifndef ONLY_MOUSE_MOVE_RAW |
52 /* States */ | 63 /* States */ |
53 shape_t *last; | 64 shape_t *last; |
54 #endif | 65 #endif |
66 | |
67 #ifdef XSHM | |
68 XImage *ximage; | |
69 XShmSegmentInfo shminfo; | |
70 #endif | |
71 | |
72 /* For handle connection */ | |
73 int io_hdl; | |
74 | |
75 /* | |
76 * Following variables are used by handle_single_x_event() | |
77 */ | |
78 int last_evt_type; /* Type of last event */ | |
79 int eflag; | |
80 int ex1, ey1, ex2, ey2; /* Aggregate expose events */ | |
81 int mflag; | |
82 int mx, my; /* Position of last motion event */ | |
83 int mbut_state; /* Button state of last motion event */ | |
55 }; | 84 }; |
85 | |
86 static void _x_supp_handle_x_event(X_supp_runtime_t *rt); | |
87 | |
88 /*! \defgroup x_supp_io IO manager for X. | |
89 * @{ | |
90 */ | |
91 #define MAX_MONITORS 200 | |
92 | |
93 typedef struct { | |
94 int type; | |
95 int fd; | |
96 mb_IO_cb_t cb; | |
97 void *data; | |
98 } monitor_t; | |
99 | |
100 struct _X_supp_IO_man { | |
101 mb_IO_man_t io_man; | |
102 monitor_t monitors[MAX_MONITORS]; | |
103 int n_monitor; | |
104 }; | |
105 | |
106 static int _x_supp_io_man_reg(struct _mb_IO_man *io_man, | |
107 int fd, MB_IO_TYPE type, | |
108 mb_IO_cb_t cb, void *data); | |
109 static void _x_supp_io_man_unreg(struct _mb_IO_man *io_man, int io_hdl); | |
110 static mb_IO_man_t *_x_supp_io_man_new(void); | |
111 static void _x_supp_io_man_free(mb_IO_man_t *io_man); | |
112 | |
113 static mb_IO_factory_t _X_supp_default_io_factory = { | |
114 _x_supp_io_man_new, | |
115 _x_supp_io_man_free | |
116 }; | |
117 static mb_IO_factory_t *_io_factory = &_X_supp_default_io_factory; | |
118 | |
119 static struct _X_supp_IO_man _default_io_man = { | |
120 {_x_supp_io_man_reg, _x_supp_io_man_unreg}, | |
121 {}, /* monitors */ | |
122 0 /* n_monitor */ | |
123 }; | |
124 | |
125 static mb_IO_man_t * | |
126 _x_supp_io_man_new(void) { | |
127 return (mb_IO_man_t *)&_default_io_man; | |
128 } | |
129 | |
130 static void | |
131 _x_supp_io_man_free(mb_IO_man_t *io_man) { | |
132 } | |
133 | |
134 static int | |
135 _x_supp_io_man_reg(struct _mb_IO_man *io_man, | |
136 int fd, MB_IO_TYPE type, mb_IO_cb_t cb, void *data) { | |
137 struct _X_supp_IO_man *xmb_io_man = (struct _X_supp_IO_man *)io_man; | |
138 int i; | |
139 | |
140 for(i = 0; i < xmb_io_man->n_monitor; i++) { | |
141 if (xmb_io_man->monitors[i].type == MB_IO_DUMMY) | |
142 break; | |
143 } | |
144 if (i == MAX_MONITORS) | |
145 return ERR; | |
146 | |
147 xmb_io_man->monitors[i].type = type; | |
148 xmb_io_man->monitors[i].fd = fd; | |
149 xmb_io_man->monitors[i].cb = cb; | |
150 xmb_io_man->monitors[i].data = data; | |
151 i++; | |
152 if(i > xmb_io_man->n_monitor) | |
153 xmb_io_man->n_monitor = i; | |
154 return i - 1; | |
155 } | |
156 | |
157 static void | |
158 _x_supp_io_man_unreg(struct _mb_IO_man *io_man, int io_hdl) { | |
159 struct _X_supp_IO_man *xmb_io_man = (struct _X_supp_IO_man *)io_man; | |
160 | |
161 ASSERT(io_hdl < xmb_io_man->n_monitor); | |
162 xmb_io_man->monitors[io_hdl].type = MB_IO_DUMMY; | |
163 } | |
164 | |
165 /*! \brief Handle connection coming data and timeout of timers. | |
166 * | |
167 * \param display is a Display returned by XOpenDisplay(). | |
168 * \param rdman is a redraw manager. | |
169 * \param tman is a timer manager. | |
170 * | |
171 * The display is managed by specified rdman and tman. rdman draws | |
172 * on the display, and tman trigger actions according timers. | |
173 */ | |
174 static void | |
175 _x_supp_event_loop(mb_rt_t *rt) { | |
176 struct _X_supp_runtime *xmb_rt = (struct _X_supp_runtime *)rt; | |
177 struct _X_supp_IO_man *io_man = (struct _X_supp_IO_man *)xmb_rt->io_man; | |
178 mb_timer_man_t *timer_man = (mb_timer_man_t *)xmb_rt->timer_man; | |
179 redraw_man_t *rdman; | |
180 mb_tman_t *tman = tman_timer_man_get_tman(timer_man); | |
181 mb_timeval_t now, tmo; | |
182 struct timeval tv; | |
183 fd_set rfds, wfds; | |
184 int nfds = 0; | |
185 int r, r1,i; | |
186 | |
187 rdman = mb_runtime_rdman(rt); | |
188 | |
189 _x_supp_handle_x_event(xmb_rt); | |
190 | |
191 while(1) { | |
192 FD_ZERO(&rfds); | |
193 FD_ZERO(&wfds); | |
194 for(i = 0; i < io_man->n_monitor; i++) { | |
195 if(io_man->monitors[i].type == MB_IO_R || | |
196 io_man->monitors[i].type == MB_IO_RW) { | |
197 FD_SET(io_man->monitors[i].fd, &rfds); | |
198 nfds = MB_MAX(nfds, io_man->monitors[i].fd + 1); | |
199 } | |
200 if(io_man->monitors[i].type == MB_IO_W || | |
201 io_man->monitors[i].type == MB_IO_RW) { | |
202 FD_SET(io_man->monitors[i].fd, &wfds); | |
203 nfds = MB_MAX(nfds, io_man->monitors[i].fd + 1); | |
204 } | |
205 } | |
206 | |
207 get_now(&now); | |
208 r = mb_tman_next_timeout(tman, &now, &tmo); | |
209 | |
210 if(r == 0) { | |
211 tv.tv_sec = MB_TIMEVAL_SEC(&tmo); | |
212 tv.tv_usec = MB_TIMEVAL_USEC(&tmo); | |
213 r1 = select(nfds, &rfds, NULL, NULL, &tv); | |
214 } else | |
215 r1 = select(nfds, &rfds, NULL, NULL, NULL); | |
216 | |
217 if(r1 == -1) { | |
218 perror("select"); | |
219 break; | |
220 } | |
221 | |
222 if(r1 == 0) { | |
223 get_now(&now); | |
224 mb_tman_handle_timeout(tman, &now); | |
225 rdman_redraw_changed(rdman); | |
226 #ifdef XSHM | |
227 XSHM_update(xmb_rt); | |
228 #endif | |
229 XFlush(xmb_rt->display); | |
230 } else { | |
231 for(i = 0; i < io_man->n_monitor; i++) { | |
232 if(io_man->monitors[i].type == MB_IO_R || | |
233 io_man->monitors[i].type == MB_IO_RW) { | |
234 if(FD_ISSET(io_man->monitors[i].fd, &rfds)) | |
235 io_man->monitors[i].cb(i, io_man->monitors[i].fd, | |
236 MB_IO_R, | |
237 io_man->monitors[i].data); | |
238 } | |
239 if(io_man->monitors[i].type == MB_IO_W || | |
240 io_man->monitors[i].type == MB_IO_RW) { | |
241 if(FD_ISSET(io_man->monitors[i].fd, &wfds)) | |
242 io_man->monitors[i].cb(i, io_man->monitors[i].fd, | |
243 MB_IO_W, | |
244 io_man->monitors[i].data); | |
245 } | |
246 } | |
247 } | |
248 } | |
249 } | |
250 | |
251 /* @} */ | |
252 | |
253 #ifdef XSHM | |
254 static void | |
255 XSHM_update(X_supp_runtime_t *xmb_rt) { | |
256 GC gc; | |
257 | |
258 gc = DefaultGC(xmb_rt->display, DefaultScreen(xmb_rt->display)); | |
259 if(xmb_rt->ximage) { /* support XSHM */ | |
260 XShmPutImage(xmb_rt->display, | |
261 xmb_rt->win, | |
262 gc, | |
263 xmb_rt->ximage, | |
264 0, 0, 0, 0, | |
265 xmb_rt->w, xmb_rt->h, 0); | |
266 } | |
267 } | |
268 #endif | |
56 | 269 |
57 /*! \defgroup xkb X Keyboard Handling | 270 /*! \defgroup xkb X Keyboard Handling |
58 * | 271 * |
59 * Accept keyboard events from X server and delivery it to | 272 * Accept keyboard events from X server and delivery it to |
60 * application through observer pattern. There is a subject, | 273 * application through observer pattern. There is a subject, |
71 } | 284 } |
72 | 285 |
73 static int X_kb_init(X_kb_info_t *kbinfo, Display *display, | 286 static int X_kb_init(X_kb_info_t *kbinfo, Display *display, |
74 redraw_man_t *rdman) { | 287 redraw_man_t *rdman) { |
75 int n_syms; | 288 int n_syms; |
76 ob_factory_t *factory; | 289 observer_factory_t *factory; |
77 int r; | 290 int r; |
78 | 291 |
79 r = XDisplayKeycodes(display, | 292 r = XDisplayKeycodes(display, |
80 &kbinfo->keycode_min, | 293 &kbinfo->keycode_min, |
81 &kbinfo->keycode_max); | 294 &kbinfo->keycode_max); |
87 n_syms, | 300 n_syms, |
88 &kbinfo->ksym_per_code); | 301 &kbinfo->ksym_per_code); |
89 if(kbinfo->syms == NULL) | 302 if(kbinfo->syms == NULL) |
90 return ERR; | 303 return ERR; |
91 | 304 |
92 factory = rdman_get_ob_factory(rdman); | 305 factory = rdman_get_observer_factory(rdman); |
93 kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB); | 306 kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB); |
94 if(kbinfo->kbevents == NULL) | 307 if(kbinfo->kbevents == NULL) |
95 return ERR; | 308 return ERR; |
96 /*! \todo Make sure ob_factory is still need. */ | 309 /*! \todo Make sure observer_factory is still need. */ |
97 kbinfo->ob_factory = factory; | 310 kbinfo->observer_factory = factory; |
98 | 311 |
99 return OK; | 312 return OK; |
100 } | 313 } |
101 | 314 |
102 static void X_kb_destroy(X_kb_info_t *kbinfo) { | 315 static void X_kb_destroy(X_kb_info_t *kbinfo) { |
103 subject_free(kbinfo->kbevents); | 316 subject_free(kbinfo->kbevents); |
104 XFree(kbinfo->syms); | 317 XFree(kbinfo->syms); |
105 } | 318 } |
106 | 319 |
107 /*! \brief Accept X keyboard events from handle_x_event() and dispatch it. | 320 /*! \brief Accept X keyboard events from _x_supp_handle_x_event() and |
321 * dispatch it. | |
108 */ | 322 */ |
109 static void X_kb_handle_event(X_kb_info_t *kbinfo, XKeyEvent *xkey) { | 323 static void X_kb_handle_event(X_kb_info_t *kbinfo, XKeyEvent *xkey) { |
110 unsigned int code; | 324 unsigned int code; |
111 int sym; | 325 int sym; |
112 X_kb_event_t event; | 326 X_kb_event_t event; |
121 event.keycode = code; | 335 event.keycode = code; |
122 event.sym = sym; | 336 event.sym = sym; |
123 | 337 |
124 subject_notify(kbinfo->kbevents, &event.event); | 338 subject_notify(kbinfo->kbevents, &event.event); |
125 } | 339 } |
126 | |
127 /* @} */ | 340 /* @} */ |
128 | 341 |
129 static unsigned int get_button_state(unsigned int state) { | 342 static unsigned int get_button_state(unsigned int state) { |
130 unsigned int but = 0; | 343 unsigned int but = 0; |
131 | 344 |
133 but |= MOUSE_BUT1; | 346 but |= MOUSE_BUT1; |
134 if(state & Button2Mask) | 347 if(state & Button2Mask) |
135 but |= MOUSE_BUT2; | 348 but |= MOUSE_BUT2; |
136 if(state & Button3Mask) | 349 if(state & Button3Mask) |
137 but |= MOUSE_BUT3; | 350 but |= MOUSE_BUT3; |
138 | 351 |
139 return but; | 352 return but; |
140 } | 353 } |
141 | 354 |
142 static unsigned int get_button(unsigned int button) { | 355 static unsigned int get_button(unsigned int button) { |
143 switch(button) { | 356 switch(button) { |
169 mouse_event.event.type = etype; | 382 mouse_event.event.type = etype; |
170 mouse_event.x = x; | 383 mouse_event.x = x; |
171 mouse_event.y = y; | 384 mouse_event.y = y; |
172 mouse_event.but_state = state; | 385 mouse_event.but_state = state; |
173 mouse_event.button = button; | 386 mouse_event.button = button; |
174 | 387 |
175 if(IS_MBO_SHAPES(obj)) | 388 if(IS_MBO_SHAPES(obj)) |
176 subject = sh_get_mouse_event_subject((shape_t *)obj); | 389 subject = sh_get_mouse_event_subject((shape_t *)obj); |
177 else | 390 else |
178 subject = coord_get_mouse_event((coord_t *)obj); | 391 subject = coord_get_mouse_event((coord_t *)obj); |
392 | |
393 subject_notify(subject, (event_t *)&mouse_event); | |
394 } | |
395 | |
396 /*! \brief Handle motion event. | |
397 */ | |
398 static void | |
399 handle_motion_event(X_supp_runtime_t *rt) { | |
400 redraw_man_t *rdman = rt->rdman; | |
401 int x, y; | |
402 int state; | |
403 shape_t *shape; | |
404 coord_t *root; | |
405 int in_stroke; | |
179 | 406 |
180 subject_notify(subject, (event_t *)&mouse_event); | 407 x = rt->mx; |
181 } | 408 y = rt->my; |
182 | 409 state = rt->mbut_state; |
183 /*! \brief Dispatch all X events in the queue. | 410 |
184 */ | 411 shape = find_shape_at_pos(rdman, x, y, |
185 static void handle_x_event(X_MB_runtime_t *rt) { | 412 &in_stroke); |
186 Display *display = rt->display; | 413 #ifdef ONLY_MOUSE_MOVE_RAW |
414 if(shape != NULL) { | |
415 notify_coord_or_shape(rdman, (mb_obj_t *)shape, | |
416 x, y, EVT_MOUSE_MOVE_RAW, state, 0); | |
417 } else { | |
418 root = rdman_get_root(rdman); | |
419 notify_coord_or_shape(rdman, (mb_obj_t *)root, | |
420 x, y, EVT_MOUSE_MOVE_RAW, state, 0); | |
421 } | |
422 #else | |
423 if(shape != NULL) { | |
424 if(rt->last != shape) { | |
425 if(rt->last) | |
426 notify_coord_or_shape(rdman, rt->last, x, y, | |
427 EVT_MOUSE_OUT, state, 0); | |
428 notify_coord_or_shape(rdman, shape, x, y, | |
429 EVT_MOUSE_OVER, state, 0); | |
430 rt->last = shape; | |
431 } else | |
432 notify_coord_or_shape(rdman, shape, x, y, | |
433 EVT_MOUSE_MOVE, state, 0); | |
434 } else { | |
435 if(rt->last) { | |
436 notify_coord_or_shape(rdman, rt->last, x, y, | |
437 EVT_MOUSE_OUT, state, 0); | |
438 rt->last = NULL; | |
439 } | |
440 } | |
441 #endif | |
442 | |
443 rt->mflag = 0; | |
444 } | |
445 | |
446 /*! \brief Redraw exposed area. | |
447 */ | |
448 static void | |
449 handle_expose_event(X_supp_runtime_t *rt) { | |
187 redraw_man_t *rdman = rt->rdman; | 450 redraw_man_t *rdman = rt->rdman; |
188 XEvent evt, peek_evt; | 451 int ex1, ey1, ex2, ey2; |
452 | |
453 ex1 = rt->ex1; | |
454 ey1 = rt->ey1; | |
455 ex2 = rt->ex2; | |
456 ey2 = rt->ey2; | |
457 | |
458 rdman_redraw_area(rdman, ex1, ey1, (ex2 - ex1), (ey2 - ey1)); | |
459 | |
460 rt->eflag = 0; | |
461 } | |
462 | |
463 /*! \brief Handle single X event and maintain internal states. | |
464 * | |
465 * It keeps internal state in rt to improve performance. | |
466 */ | |
467 static void | |
468 handle_single_x_event(X_supp_runtime_t *rt, XEvent *evt) { | |
469 redraw_man_t *rdman = rt->rdman; | |
189 XMotionEvent *mevt; | 470 XMotionEvent *mevt; |
190 XButtonEvent *bevt; | 471 XButtonEvent *bevt; |
191 XExposeEvent *eevt; | 472 XExposeEvent *eevt; |
192 XKeyEvent *xkey; | 473 XKeyEvent *xkey; |
193 co_aix x, y, w, h; | 474 int x, y, w, h; |
194 | |
195 int eflag = 0; | |
196 int ex1=0, ey1=0, ex2=0, ey2=0; | |
197 | 475 |
198 shape_t *shape; | 476 shape_t *shape; |
199 coord_t *root; | |
200 | 477 |
201 unsigned int state, button; | 478 unsigned int state, button; |
202 int in_stroke; | 479 int in_stroke; |
480 | |
481 if(evt->type != MotionNotify && rt->mflag) | |
482 handle_motion_event(rt); | |
483 | |
484 switch(evt->type) { | |
485 case ButtonPress: | |
486 bevt = (XButtonEvent *)evt; | |
487 x = bevt->x; | |
488 y = bevt->y; | |
489 state = get_button_state(bevt->state); | |
490 button = get_button(bevt->button); | |
491 | |
492 shape = find_shape_at_pos(rdman, x, y, | |
493 &in_stroke); | |
494 if(shape) | |
495 notify_coord_or_shape(rdman, (mb_obj_t *)shape, | |
496 x, y, EVT_MOUSE_BUT_PRESS, | |
497 state, button); | |
498 break; | |
499 | |
500 case ButtonRelease: | |
501 bevt = (XButtonEvent *)evt; | |
502 x = bevt->x; | |
503 y = bevt->y; | |
504 state = get_button_state(bevt->state); | |
505 button = get_button(bevt->button); | |
506 | |
507 shape = find_shape_at_pos(rdman, x, y, | |
508 &in_stroke); | |
509 if(shape) | |
510 notify_coord_or_shape(rdman, (mb_obj_t *)shape, | |
511 x, y, EVT_MOUSE_BUT_RELEASE, | |
512 state, button); | |
513 break; | |
514 | |
515 case MotionNotify: | |
516 mevt = (XMotionEvent *)evt; | |
517 rt->mx = mevt->x; | |
518 rt->my = mevt->y; | |
519 rt->mbut_state = get_button_state(mevt->state); | |
520 rt->mflag = 1; | |
521 break; | |
522 | |
523 case KeyPress: | |
524 case KeyRelease: | |
525 xkey = &evt->xkey; | |
526 X_kb_handle_event(&rt->kbinfo, xkey); | |
527 break; | |
528 | |
529 case Expose: | |
530 eevt = &evt->xexpose; | |
531 x = eevt->x; | |
532 y = eevt->y; | |
533 w = eevt->width; | |
534 h = eevt->height; | |
535 | |
536 if(rt->eflag) { | |
537 if(x < rt->ex1) | |
538 rt->ex1 = x; | |
539 if(y < rt->ey1) | |
540 rt->ey1 = y; | |
541 if((x + w) > rt->ex2) | |
542 rt->ex2 = x + w; | |
543 if((y + h) > rt->ey2) | |
544 rt->ey2 = y + h; | |
545 } else { | |
546 rt->ex1 = x; | |
547 rt->ey1 = y; | |
548 rt->ex2 = x + w; | |
549 rt->ey2 = y + h; | |
550 rt->eflag = 1; | |
551 } | |
552 break; | |
553 } | |
554 } | |
555 | |
556 /*! \brief Call when no more event in an event iteration. | |
557 * | |
558 * No more event means event queue is emplty. This function will | |
559 * perform some actions according current internal state. | |
560 */ | |
561 static void | |
562 no_more_event(X_supp_runtime_t *rt) { | |
563 if(rt->mflag) | |
564 handle_motion_event(rt); | |
565 if(rt->eflag) | |
566 handle_expose_event(rt); | |
567 } | |
568 | |
569 /*! \brief Dispatch all X events in the queue. | |
570 */ | |
571 static void _x_supp_handle_x_event(X_supp_runtime_t *rt) { | |
572 Display *display = rt->display; | |
573 XEvent evt; | |
203 int r; | 574 int r; |
204 | 575 |
205 /* XXX: For some unknown reason, it causes a segmentation fault to | 576 /* XXX: For some unknown reason, it causes a segmentation fault to |
206 * called XEventsQueued() after receiving first Expose event | 577 * called XEventsQueued() after receiving first Expose event |
207 * and before redraw for the event. | 578 * and before redraw for the event. |
209 while(XEventsQueued(display, QueuedAfterReading) > 0) { | 580 while(XEventsQueued(display, QueuedAfterReading) > 0) { |
210 r = XNextEvent(display, &evt); | 581 r = XNextEvent(display, &evt); |
211 if(r == -1) | 582 if(r == -1) |
212 break; | 583 break; |
213 | 584 |
214 switch(evt.type) { | 585 handle_single_x_event(rt, &evt); |
215 case ButtonPress: | 586 } |
216 bevt = (XButtonEvent *)&evt; | 587 no_more_event(rt); |
217 x = bevt->x; | 588 |
218 y = bevt->y; | 589 #ifdef XSHM |
219 state = get_button_state(bevt->state); | 590 XSHM_update(rt); |
220 button = get_button(bevt->button); | |
221 | |
222 shape = find_shape_at_pos(rdman, x, y, | |
223 &in_stroke); | |
224 if(shape) | |
225 notify_coord_or_shape(rdman, (mb_obj_t *)shape, | |
226 x, y, EVT_MOUSE_BUT_PRESS, | |
227 state, button); | |
228 break; | |
229 | |
230 case ButtonRelease: | |
231 bevt = (XButtonEvent *)&evt; | |
232 x = bevt->x; | |
233 y = bevt->y; | |
234 state = get_button_state(bevt->state); | |
235 button = get_button(bevt->button); | |
236 | |
237 shape = find_shape_at_pos(rdman, x, y, | |
238 &in_stroke); | |
239 if(shape) | |
240 notify_coord_or_shape(rdman, (mb_obj_t *)shape, | |
241 x, y, EVT_MOUSE_BUT_RELEASE, | |
242 state, button); | |
243 break; | |
244 | |
245 case MotionNotify: | |
246 while(XEventsQueued(display, QueuedAfterReading) > 0) { | |
247 r = XPeekEvent(display, &peek_evt); | |
248 if(r == -1) | |
249 break; | |
250 if(peek_evt.type != MotionNotify) | |
251 break; | |
252 XNextEvent(display, &evt); | |
253 } | |
254 if(r == -1) | |
255 break; | |
256 | |
257 mevt = (XMotionEvent *)&evt; | |
258 x = mevt->x; | |
259 y = mevt->y; | |
260 state = get_button_state(mevt->state); | |
261 | |
262 shape = find_shape_at_pos(rdman, x, y, | |
263 &in_stroke); | |
264 #ifdef ONLY_MOUSE_MOVE_RAW | |
265 if(shape != NULL) { | |
266 notify_coord_or_shape(rdman, (mb_obj_t *)shape, | |
267 x, y, EVT_MOUSE_MOVE_RAW, state, 0); | |
268 } else { | |
269 root = rdman_get_root(rdman); | |
270 notify_coord_or_shape(rdman, (mb_obj_t *)root, | |
271 x, y, EVT_MOUSE_MOVE_RAW, state, 0); | |
272 } | |
273 #else | |
274 if(shape != NULL) { | |
275 if(rt->last != shape) { | |
276 if(rt->last) | |
277 notify_coord_or_shape(rdman, rt->last, x, y, | |
278 EVT_MOUSE_OUT, state, 0); | |
279 notify_coord_or_shape(rdman, shape, x, y, | |
280 EVT_MOUSE_OVER, state, 0); | |
281 rt->last = shape; | |
282 } else | |
283 notify_coord_or_shape(rdman, shape, x, y, | |
284 EVT_MOUSE_MOVE, state, 0); | |
285 } else { | |
286 if(rt->last) { | |
287 notify_coord_or_shape(rdman, rt->last, x, y, | |
288 EVT_MOUSE_OUT, state, 0); | |
289 rt->last = NULL; | |
290 } | |
291 } | |
292 #endif | 591 #endif |
293 break; | |
294 | |
295 case KeyPress: | |
296 case KeyRelease: | |
297 xkey = &evt.xkey; | |
298 X_kb_handle_event(&rt->kbinfo, xkey); | |
299 break; | |
300 | |
301 case Expose: | |
302 eevt = &evt.xexpose; | |
303 x = eevt->x; | |
304 y = eevt->y; | |
305 w = eevt->width; | |
306 h = eevt->height; | |
307 | |
308 if(eflag) { | |
309 if(x < ex1) | |
310 ex1 = x; | |
311 if(y < ey1) | |
312 ey1 = y; | |
313 if((x + w) > ex2) | |
314 ex2 = x + w; | |
315 if((y + h) > ey2) | |
316 ey2 = y + h; | |
317 } else { | |
318 ex1 = x; | |
319 ey1 = y; | |
320 ex2 = x + w; | |
321 ey2 = y + h; | |
322 eflag = 1; | |
323 } | |
324 break; | |
325 } | |
326 } | |
327 if(eflag) { | |
328 rdman_redraw_area(rdman, ex1, ey1, (ex2 - ex1), (ey2 - ey1)); | |
329 eflag = 0; | |
330 } | |
331 XFlush(display); | 592 XFlush(display); |
332 } | 593 } |
333 | 594 |
334 /*! \brief Handle connection coming data and timeout of timers. | 595 static void |
335 * | 596 _x_supp_handle_connection(int hdl, int fd, MB_IO_TYPE type, void *data) { |
336 * \param display is a Display returned by XOpenDisplay(). | 597 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *)data; |
337 * \param rdman is a redraw manager. | 598 |
338 * \param tman is a timer manager. | 599 _x_supp_handle_x_event(xmb_rt); |
339 * | 600 } |
340 * The display is managed by specified rdman and tman. rdman draws | |
341 * on the display, and tman trigger actions according timers. | |
342 */ | |
343 void X_MB_handle_connection(void *be) { | |
344 X_MB_runtime_t *rt = (X_MB_runtime_t *) be; | |
345 Display *display = rt->display; | |
346 redraw_man_t *rdman = rt->rdman; | |
347 mb_tman_t *tman = rt->tman; | |
348 int fd; | |
349 mb_timeval_t now, tmo; | |
350 struct timeval tv; | |
351 fd_set rfds,wfds; | |
352 int nfds; | |
353 int r, r1,i; | |
354 | |
355 handle_x_event(rt); | |
356 | |
357 fd = XConnectionNumber(display); | |
358 nfds = fd + 1; | |
359 while(1) { | |
360 FD_ZERO(&rfds); | |
361 FD_ZERO(&wfds); | |
362 FD_SET(fd, &rfds); | |
363 for(i=0;i<rt->n_monitor;i++) { | |
364 if (rt->monitors[i].type == MONITOR_READ) | |
365 FD_SET(rt->monitors[i].fd, &rfds); | |
366 else if (rt->monitors[i].type == MONITOR_WRITE) | |
367 FD_SET(rt->monitors[i].fd, &wfds); | |
368 } | |
369 | |
370 get_now(&now); | |
371 r = mb_tman_next_timeout(tman, &now, &tmo); | |
372 | |
373 if(r == 0) { | |
374 tv.tv_sec = MB_TIMEVAL_SEC(&tmo); | |
375 tv.tv_usec = MB_TIMEVAL_USEC(&tmo); | |
376 r1 = select(nfds, &rfds, NULL, NULL, &tv); | |
377 } else | |
378 r1 = select(nfds, &rfds, NULL, NULL, NULL); | |
379 | |
380 if(r1 == -1) { | |
381 perror("select"); | |
382 break; | |
383 } | |
384 | |
385 if(r1 == 0) { | |
386 get_now(&now); | |
387 mb_tman_handle_timeout(tman, &now); | |
388 rdman_redraw_changed(rdman); | |
389 XFlush(display); | |
390 } else if(FD_ISSET(fd, &rfds)){ | |
391 handle_x_event(rt); | |
392 } else { | |
393 for(i=0;i<rt->n_monitor;i++) { | |
394 if (rt->monitors[i].type == MONITOR_READ) | |
395 if (FD_ISSET(rt->monitors[i].fd, &rfds)) | |
396 rt->monitors[i].f(rt->monitors[i].fd,rt->monitors[i].arg); | |
397 else if (rt->monitors[i].type == MONITOR_WRITE) | |
398 if (FD_ISSET(rt->monitors[i].fd, &wfds)) | |
399 rt->monitors[i].f(rt->monitors[i].fd,rt->monitors[i].arg); | |
400 } | |
401 } | |
402 } | |
403 } | |
404 | |
405 #define ERR -1 | |
406 #define OK 0 | |
407 | 601 |
408 static int X_init_connection(const char *display_name, | 602 static int X_init_connection(const char *display_name, |
409 int w, int h, | 603 int w, int h, |
410 Display **displayp, | 604 Display **displayp, |
411 Visual **visualp, | 605 Visual **visualp, |
415 Visual *visual; | 609 Visual *visual; |
416 int screen; | 610 int screen; |
417 XSetWindowAttributes wattr; | 611 XSetWindowAttributes wattr; |
418 int depth; | 612 int depth; |
419 int x, y; | 613 int x, y; |
614 int draw_root = 0; | |
615 const char *disp_name; | |
616 char disp_buf[32]; | |
617 int cp; | |
420 int r; | 618 int r; |
421 | 619 |
422 display = XOpenDisplay(display_name); | 620 /* |
621 * Support drawing on the root window. | |
622 */ | |
623 disp_name = display_name; | |
624 if(strstr(display_name, ":root") != NULL) { | |
625 draw_root = 1; | |
626 cp = strlen(display_name) - 5; | |
627 if(cp >= 32) | |
628 cp = 31; | |
629 memcpy(disp_buf, display_name, cp); | |
630 disp_buf[cp] = 0; | |
631 disp_name = disp_buf; | |
632 } | |
633 | |
634 display = XOpenDisplay(disp_name); | |
423 if(display == NULL) | 635 if(display == NULL) |
424 return ERR; | 636 return ERR; |
425 | 637 |
426 screen = DefaultScreen(display); | 638 screen = DefaultScreen(display); |
427 root = DefaultRootWindow(display); | 639 root = DefaultRootWindow(display); |
428 visual = DefaultVisual(display, screen); | 640 visual = DefaultVisual(display, screen); |
429 depth = DefaultDepth(display, screen); | 641 depth = DefaultDepth(display, screen); |
430 wattr.override_redirect = False; | 642 wattr.override_redirect = False; |
431 x = 10; | 643 x = 10; |
432 y = 10; | 644 y = 10; |
433 win = XCreateWindow(display, root, | 645 if(draw_root) |
434 x, y, | 646 win = RootWindowOfScreen(ScreenOfDisplay(display, screen)); |
435 w, h, | 647 else { |
436 1, depth, InputOutput, visual, | 648 win = XCreateWindow(display, root, |
437 CWOverrideRedirect, &wattr); | 649 x, y, |
438 r = XMapWindow(display, win); | 650 w, h, |
439 if(r == -1) { | 651 1, depth, InputOutput, visual, |
440 XCloseDisplay(display); | 652 CWOverrideRedirect, &wattr); |
441 return ERR; | 653 r = XMapWindow(display, win); |
654 if(r == -1) { | |
655 XCloseDisplay(display); | |
656 return ERR; | |
657 } | |
442 } | 658 } |
443 | 659 |
444 XSelectInput(display, win, PointerMotionMask | ExposureMask | | 660 XSelectInput(display, win, PointerMotionMask | ExposureMask | |
445 ButtonPressMask | ButtonReleaseMask | | 661 ButtonPressMask | ButtonReleaseMask | |
446 KeyPressMask | KeyReleaseMask); | 662 KeyPressMask | KeyReleaseMask); |
451 *winp = win; | 667 *winp = win; |
452 | 668 |
453 return OK; | 669 return OK; |
454 } | 670 } |
455 | 671 |
672 #ifdef XSHM | |
673 static void | |
674 xshm_destroy(X_supp_runtime_t *xmb_rt) { | |
675 XShmSegmentInfo *shminfo; | |
676 | |
677 shminfo = &xmb_rt->shminfo; | |
678 | |
679 if(xmb_rt->shminfo.shmaddr) { | |
680 XShmDetach(xmb_rt->display, shminfo); | |
681 } | |
682 | |
683 if(xmb_rt->ximage) { | |
684 XDestroyImage(xmb_rt->ximage); | |
685 xmb_rt->ximage = NULL; | |
686 } | |
687 | |
688 if(shminfo->shmaddr) { | |
689 shmdt(shminfo->shmaddr); | |
690 shminfo->shmaddr = NULL; | |
691 } | |
692 | |
693 if(shminfo->shmid) { | |
694 shmctl(shminfo->shmid, IPC_RMID, 0); | |
695 shminfo->shmid = 0; | |
696 } | |
697 } | |
698 | |
699 static void | |
700 xshm_init(X_supp_runtime_t *xmb_rt) { | |
701 Display *display; | |
702 Visual *visual; | |
703 XImage *ximage; | |
704 int screen; | |
705 int depth; | |
706 int support_shm; | |
707 int mem_sz; | |
708 XShmSegmentInfo *shminfo; | |
709 int surf_fmt; | |
710 | |
711 display = xmb_rt->display; | |
712 visual = xmb_rt->visual; | |
713 shminfo = &xmb_rt->shminfo; | |
714 | |
715 support_shm = XShmQueryExtension(display); | |
716 if(!support_shm) | |
717 return; | |
718 | |
719 screen = DefaultScreen(display); | |
720 depth = DefaultDepth(display, screen); | |
721 | |
722 if(depth != 24 && depth != 32) | |
723 return; | |
724 | |
725 xmb_rt->ximage = XShmCreateImage(display, visual, depth, | |
726 ZPixmap, NULL, shminfo, | |
727 xmb_rt->w, xmb_rt->h); | |
728 ximage = xmb_rt->ximage; | |
729 | |
730 mem_sz = ximage->bytes_per_line * ximage->height; | |
731 shminfo->shmid = shmget(IPC_PRIVATE, mem_sz, IPC_CREAT | 0777); | |
732 if(shminfo->shmid == -1) { | |
733 xshm_destroy(xmb_rt); | |
734 return; | |
735 } | |
736 | |
737 shminfo->shmaddr = shmat(shminfo->shmid, 0, 0); | |
738 ximage->data = shminfo->shmaddr; | |
739 | |
740 shminfo->readOnly = 0; | |
741 | |
742 XShmAttach(display, shminfo); | |
743 | |
744 switch(depth) { | |
745 case 24: surf_fmt = CAIRO_FORMAT_RGB24; break; | |
746 case 32: surf_fmt = CAIRO_FORMAT_ARGB32; break; | |
747 } | |
748 | |
749 xmb_rt->backend_surface = | |
750 mbe_image_surface_create_for_data((unsigned char *)ximage->data, | |
751 surf_fmt, | |
752 xmb_rt->w, | |
753 xmb_rt->h, | |
754 ximage->bytes_per_line); | |
755 if(xmb_rt->backend_surface == NULL) | |
756 xshm_destroy(xmb_rt); | |
757 } | |
758 #endif /* XSHM */ | |
759 | |
456 /*! \brief Initialize a MadButterfy runtime for Xlib. | 760 /*! \brief Initialize a MadButterfy runtime for Xlib. |
457 * | 761 * |
458 * It setups a runtime environment to run MadButterfly with Xlib. | 762 * This one is very like _x_supp_init(), except it accepts a |
459 * Users should specify width and height of the opening window. | 763 * X_supp_runtime_t object initialized with a display connected to a X |
460 */ | 764 * server and an opened window. |
461 static int X_MB_init(const char *display_name, | 765 * |
462 int w, int h, X_MB_runtime_t *xmb_rt) { | 766 * Following field of the X_supp_runtime_t object should be initialized. |
767 * - w, h | |
768 * - win | |
769 * - display | |
770 * - visual | |
771 */ | |
772 static int | |
773 _x_supp_init_with_win_internal(X_supp_runtime_t *xmb_rt) { | |
463 mb_img_ldr_t *img_ldr; | 774 mb_img_ldr_t *img_ldr; |
464 | 775 int w, h; |
465 memset(xmb_rt, 0, sizeof(X_MB_runtime_t)); | 776 int disp_fd; |
466 | 777 |
467 xmb_rt->w = w; | 778 w = xmb_rt->w; |
468 xmb_rt->h = h; | 779 h = xmb_rt->h; |
469 X_init_connection(display_name, w, h, &xmb_rt->display, | 780 |
470 &xmb_rt->visual, &xmb_rt->win); | 781 #ifdef XSHM |
471 #ifdef OPENVG_GRAPH_ENGINE | 782 xshm_init(xmb_rt); |
472 _ge_openvg_disp_id = xmb_rt->display; | |
473 #endif | 783 #endif |
474 | |
475 mbe_init(); | |
476 | 784 |
477 xmb_rt->surface = | 785 xmb_rt->surface = |
478 mbe_image_surface_create(MB_IFMT_ARGB32, w, h); | 786 mbe_image_surface_create(MB_IFMT_ARGB32, w, h); |
479 | 787 |
480 xmb_rt->surface_ptn = | 788 xmb_rt->surface_ptn = |
481 mbe_pattern_create_for_surface(xmb_rt->surface); | 789 mbe_pattern_create_for_surface(xmb_rt->surface); |
482 | 790 |
483 #ifdef OPENVG_GRAPH_ENGINE | 791 if(xmb_rt->backend_surface == NULL) /* xshm_init() may create one */ |
484 xmb_rt->backend_surface = | 792 xmb_rt->backend_surface = |
485 mbe_vg_win_surface_create(xmb_rt->display, | 793 mbe_xlib_surface_create(xmb_rt->display, |
486 xmb_rt->win, | 794 xmb_rt->win, |
487 xmb_rt->visual, | 795 xmb_rt->visual, |
488 w, h); | 796 w, h); |
489 #else | |
490 xmb_rt->backend_surface = | |
491 mbe_xlib_surface_create(xmb_rt->display, | |
492 xmb_rt->win, | |
493 xmb_rt->visual, | |
494 w, h); | |
495 #endif | |
496 | 797 |
497 xmb_rt->cr = mbe_create(xmb_rt->surface); | 798 xmb_rt->cr = mbe_create(xmb_rt->surface); |
498 xmb_rt->backend_cr = mbe_create(xmb_rt->backend_surface); | 799 xmb_rt->backend_cr = mbe_create(xmb_rt->backend_surface); |
499 | 800 |
500 /* TODO: Remove this line. Since we use mbe_copy_source(), it | |
501 * will set source for the backend. So, this line is redundants. | |
502 * It can be removed. sourface_ptn can be removed, too. | |
503 */ | |
504 mbe_set_source(xmb_rt->backend_cr, xmb_rt->surface_ptn); | 801 mbe_set_source(xmb_rt->backend_cr, xmb_rt->surface_ptn); |
505 | 802 |
506 xmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t)); | 803 xmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t)); |
507 redraw_man_init(xmb_rt->rdman, xmb_rt->cr, xmb_rt->backend_cr); | 804 redraw_man_init(xmb_rt->rdman, xmb_rt->cr, xmb_rt->backend_cr); |
508 // FIXME: This is a wired loopback reference. This is inly required when we need | 805 // FIXME: This is a wired loopback reference. This is inly required when we need |
509 // to get the xmb_rt->tman for the animation. We should relocate the tman | 806 // to get the xmb_rt->tman for the animation. We should relocate the tman |
510 // to the redraw_man_t instead. | 807 // to the redraw_man_t instead. |
511 xmb_rt->rdman->rt = xmb_rt; | 808 xmb_rt->rdman->rt = xmb_rt; |
512 xmb_rt->rdman->w = w; | 809 |
513 xmb_rt->rdman->h = h; | 810 xmb_rt->io_man = mb_io_man_new(_io_factory); |
514 | 811 xmb_rt->timer_man = mb_timer_man_new(_timer_factory); |
515 xmb_rt->tman = mb_tman_new(); | |
516 | 812 |
517 img_ldr = simple_mb_img_ldr_new(""); | 813 img_ldr = simple_mb_img_ldr_new(""); |
518 xmb_rt->img_ldr = img_ldr; | 814 xmb_rt->img_ldr = img_ldr; |
519 rdman_set_img_ldr(xmb_rt->rdman, img_ldr); | 815 /*! \todo Remove rdman_set_img_ldr() */ |
520 memset(xmb_rt->monitors,0,sizeof(xmb_rt->monitors)); | 816 rdman_set_img_ldr(xmb_rt->rdman, img_ldr); /* this is ncessary? */ |
521 | 817 |
522 #ifndef ONLY_MOUSE_MOVE_RAW | 818 #ifndef ONLY_MOUSE_MOVE_RAW |
523 xmb_rt->last = NULL; | 819 xmb_rt->last = NULL; |
524 #endif | 820 #endif |
525 | 821 |
526 X_kb_init(&xmb_rt->kbinfo, xmb_rt->display, xmb_rt->rdman); | 822 X_kb_init(&xmb_rt->kbinfo, xmb_rt->display, xmb_rt->rdman); |
527 | 823 |
824 disp_fd = XConnectionNumber(xmb_rt->display); | |
825 xmb_rt->io_hdl = mb_io_man_reg(xmb_rt->io_man, disp_fd, | |
826 MB_IO_R, | |
827 _x_supp_handle_connection, | |
828 xmb_rt); | |
829 | |
528 return OK; | 830 return OK; |
529 } | 831 } |
530 | 832 |
531 static void X_MB_destroy(X_MB_runtime_t *xmb_rt) { | 833 /*! \brief Initialize a MadButterfy runtime for Xlib. |
834 * | |
835 * It setups a runtime environment to run MadButterfly with Xlib. | |
836 * Users should specify width and height of the opening window. | |
837 */ | |
838 static int _x_supp_init(X_supp_runtime_t *xmb_rt, const char *display_name, | |
839 int w, int h) { | |
840 int r; | |
841 | |
842 memset(xmb_rt, 0, sizeof(X_supp_runtime_t)); | |
843 | |
844 xmb_rt->w = w; | |
845 xmb_rt->h = h; | |
846 r = X_init_connection(display_name, w, h, &xmb_rt->display, | |
847 &xmb_rt->visual, &xmb_rt->win); | |
848 if(r != OK) | |
849 return ERR; | |
850 | |
851 r = _x_supp_init_with_win_internal(xmb_rt); | |
852 | |
853 return r; | |
854 } | |
855 | |
856 /*! \brief Initialize a MadButterfly runtime for a window of X. | |
857 * | |
858 * Runtimes initialized with this function should be destroyed with | |
859 * x_supp_destroy_keep_win(). | |
860 */ | |
861 static int | |
862 _x_supp_init_with_win(X_supp_runtime_t *xmb_rt, | |
863 Display *display, Window win) { | |
864 XWindowAttributes attrs; | |
865 int r; | |
866 | |
867 r = XGetWindowAttributes(display, win, &attrs); | |
868 if(r == 0) | |
869 return ERR; | |
870 | |
871 memset(xmb_rt, 0, sizeof(X_supp_runtime_t)); | |
872 | |
873 xmb_rt->display = display; | |
874 xmb_rt->win = win; | |
875 xmb_rt->visual = attrs.visual; | |
876 xmb_rt->w = attrs.width; | |
877 xmb_rt->h = attrs.height; | |
878 | |
879 r = _x_supp_init_with_win_internal(xmb_rt); | |
880 | |
881 return r; | |
882 } | |
883 | |
884 static void x_supp_destroy(X_supp_runtime_t *xmb_rt) { | |
532 if(xmb_rt->rdman) { | 885 if(xmb_rt->rdman) { |
533 redraw_man_destroy(xmb_rt->rdman); | 886 redraw_man_destroy(xmb_rt->rdman); |
534 free(xmb_rt->rdman); | 887 free(xmb_rt->rdman); |
535 } | 888 } |
536 | 889 |
537 if(xmb_rt->tman) | 890 if(xmb_rt->io_hdl) |
538 mb_tman_free(xmb_rt->tman); | 891 mb_io_man_unreg(xmb_rt->io_man, xmb_rt->io_hdl); |
892 | |
893 if(xmb_rt->io_man) | |
894 mb_io_man_free(_io_factory, xmb_rt->io_man); | |
895 if(xmb_rt->timer_man) | |
896 mb_timer_man_free(_timer_factory, xmb_rt->timer_man); | |
539 | 897 |
540 if(xmb_rt->img_ldr) | 898 if(xmb_rt->img_ldr) |
541 MB_IMG_LDR_FREE(xmb_rt->img_ldr); | 899 MB_IMG_LDR_FREE(xmb_rt->img_ldr); |
542 | 900 |
543 if(xmb_rt->cr) | 901 if(xmb_rt->cr) |
556 XCloseDisplay(xmb_rt->display); | 914 XCloseDisplay(xmb_rt->display); |
557 | 915 |
558 X_kb_destroy(&xmb_rt->kbinfo); | 916 X_kb_destroy(&xmb_rt->kbinfo); |
559 } | 917 } |
560 | 918 |
561 void *X_MB_new(const char *display_name, int w, int h) { | 919 /*! \brief Destroy a MadButterfly runtime initialized with |
562 X_MB_runtime_t *rt; | 920 * _x_supp_init_with_win(). |
921 * | |
922 * Destroying a runtime with this function prevent the window and | |
923 * display associated with the runtime being closed. | |
924 */ | |
925 static void | |
926 x_supp_destroy_keep_win(X_supp_runtime_t *xmb_rt) { | |
927 Display *display; | |
928 Window win; | |
929 | |
930 display = xmb_rt->display; | |
931 xmb_rt->display = NULL; | |
932 win = xmb_rt->win; | |
933 xmb_rt->win = 0; | |
934 | |
935 x_supp_destroy(xmb_rt); | |
936 | |
937 xmb_rt->display = display; | |
938 xmb_rt->win = win; | |
939 } | |
940 | |
941 static mb_rt_t * | |
942 _x_supp_new(const char *display_name, int w, int h) { | |
943 X_supp_runtime_t *rt; | |
563 int r; | 944 int r; |
564 | 945 |
565 rt = O_ALLOC(X_MB_runtime_t); | 946 rt = O_ALLOC(X_supp_runtime_t); |
566 if(rt == NULL) | 947 if(rt == NULL) |
567 return NULL; | 948 return NULL; |
568 | 949 |
569 r = X_MB_init(display_name, w, h, rt); | 950 r = _x_supp_init(rt, display_name, w, h); |
570 if(r != OK) { | 951 if(r != OK) { |
571 free(rt); | 952 free(rt); |
572 return NULL; | 953 return NULL; |
573 } | 954 } |
574 | 955 |
575 return rt; | 956 return (mb_rt_t *)rt; |
576 } | 957 } |
577 | 958 |
578 void X_MB_free(void *rt) { | 959 /*! \brief Create a new runtime for existed window for X. |
579 X_MB_destroy((X_MB_runtime_t *) rt); | 960 * |
961 * The object returned by this function must be free with | |
962 * _x_supp_free_keep_win() to prevent the window from closed. | |
963 */ | |
964 static mb_rt_t * | |
965 _x_supp_new_with_win(MB_DISPLAY display, MB_WINDOW win) { | |
966 X_supp_runtime_t *rt; | |
967 int r; | |
968 | |
969 rt = O_ALLOC(X_supp_runtime_t); | |
970 if(rt == NULL) | |
971 return NULL; | |
972 | |
973 r = _x_supp_init_with_win(rt, display, win); | |
974 if(r != OK) { | |
975 free(rt); | |
976 return NULL; | |
977 } | |
978 | |
979 return (mb_rt_t *)rt; | |
980 } | |
981 | |
982 static void | |
983 _x_supp_free(mb_rt_t *rt) { | |
984 x_supp_destroy((X_supp_runtime_t *) rt); | |
580 free(rt); | 985 free(rt); |
581 } | 986 } |
582 | 987 |
583 subject_t *X_MB_kbevents(void *rt) { | 988 /*! \brief Free runtime created with _x_supp_new_with_win(). |
584 X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; | 989 */ |
990 static void | |
991 _x_supp_free_keep_win(mb_rt_t *rt) { | |
992 x_supp_destroy_keep_win((X_supp_runtime_t *) rt); | |
993 free(rt); | |
994 } | |
995 | |
996 static subject_t * | |
997 _x_supp_kbevents(mb_rt_t *rt) { | |
998 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; | |
585 return xmb_rt->kbinfo.kbevents; | 999 return xmb_rt->kbinfo.kbevents; |
586 } | 1000 } |
587 | 1001 |
588 redraw_man_t *X_MB_rdman(void *rt) { | 1002 static redraw_man_t * |
589 X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; | 1003 _x_supp_rdman(mb_rt_t *rt) { |
1004 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; | |
590 return xmb_rt->rdman; | 1005 return xmb_rt->rdman; |
591 } | 1006 } |
592 | 1007 |
593 mb_tman_t *X_MB_tman(void *rt) { | 1008 static mb_timer_man_t * |
594 X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; | 1009 _x_supp_timer_man(mb_rt_t *rt) { |
595 return xmb_rt->tman; | 1010 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; |
596 } | 1011 return xmb_rt->timer_man; |
597 | 1012 } |
598 ob_factory_t *X_MB_ob_factory(void *rt) { | 1013 |
599 X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; | 1014 static observer_factory_t * |
600 ob_factory_t *factory; | 1015 _x_supp_observer_factory(mb_rt_t *rt) { |
601 | 1016 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; |
602 factory = rdman_get_ob_factory(xmb_rt->rdman); | 1017 observer_factory_t *factory; |
1018 | |
1019 factory = rdman_get_observer_factory(xmb_rt->rdman); | |
603 return factory; | 1020 return factory; |
604 } | 1021 } |
605 | 1022 |
606 mb_img_ldr_t *X_MB_img_ldr(void *rt) { | 1023 static mb_img_ldr_t * |
607 X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; | 1024 _x_supp_img_ldr(mb_rt_t *rt) { |
608 X_MB_runtime_t *img_ldr; | 1025 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; |
1026 mb_img_ldr_t *img_ldr; | |
609 | 1027 |
610 img_ldr = xmb_rt->img_ldr; | 1028 img_ldr = xmb_rt->img_ldr; |
611 | 1029 |
612 return img_ldr; | 1030 return img_ldr; |
613 } | 1031 } |
614 | 1032 |
615 void X_MB_add_event(void *rt, int type, int fd, mb_eventcb_t f,void *arg) | 1033 static int |
1034 _x_supp_add_event(mb_rt_t *rt, int fd, MB_IO_TYPE type, | |
1035 mb_IO_cb_t cb, void *data) | |
616 { | 1036 { |
617 X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; | 1037 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; |
618 int i; | 1038 mb_IO_man_t *io_man = xmb_rt->io_man; |
619 | 1039 int hdl; |
620 for(i=0;i<xmb_rt->n_monitor;i++) { | 1040 |
621 if (xmb_rt->monitors[i].type == type && xmb_rt->monitors[i].fd == fd) { | 1041 hdl = mb_io_man_reg(io_man, fd, type, cb, data); |
622 xmb_rt->monitors[i].f = f; | 1042 return hdl; |
623 xmb_rt->monitors[i].arg = arg; | 1043 } |
624 return; | 1044 |
625 } | 1045 static void |
626 } | 1046 _x_supp_remove_event(mb_rt_t *rt, int hdl) |
627 for(i=0;i<xmb_rt->n_monitor;i++) { | |
628 if (xmb_rt->monitors[i].type == 0) { | |
629 xmb_rt->monitors[i].type = type; | |
630 xmb_rt->monitors[i].fd = fd; | |
631 xmb_rt->monitors[i].f = f; | |
632 xmb_rt->monitors[i].arg = arg; | |
633 return; | |
634 } | |
635 } | |
636 if (i == MAX_MONITORS) return; | |
637 xmb_rt->monitors[i].type = type; | |
638 xmb_rt->monitors[i].fd = fd; | |
639 xmb_rt->monitors[i].f = f; | |
640 xmb_rt->monitors[i].arg = arg; | |
641 i++; | |
642 xmb_rt->n_monitor=i; | |
643 } | |
644 | |
645 void X_MB_remove_event(void *rt, int type, int fd) | |
646 { | 1047 { |
647 X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; | 1048 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; |
648 int i; | 1049 mb_IO_man_t *io_man = xmb_rt->io_man; |
649 for(i=0;i<xmb_rt->n_monitor;i++) { | 1050 |
650 if (xmb_rt->monitors[i].type == type && xmb_rt->monitors[i].fd == fd) { | 1051 mb_io_man_unreg(io_man, hdl); |
651 xmb_rt->monitors[i].type = 0; | 1052 } |
652 return; | 1053 |
653 } | 1054 static int |
654 } | 1055 _x_supp_flush(mb_rt_t *rt) { |
655 } | 1056 X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; |
656 mb_backend_t backend = { X_MB_new, | 1057 int r; |
657 X_MB_free, | 1058 |
658 X_MB_add_event, | 1059 #ifdef XSHM |
659 X_MB_remove_event, | 1060 XSHM_update(xmb_rt); |
660 X_MB_handle_connection, | 1061 #endif |
661 X_MB_kbevents, | 1062 r = XFlush(xmb_rt->display); |
662 X_MB_rdman, | 1063 return r == 0? ERR: OK; |
663 X_MB_tman, | 1064 } |
664 X_MB_ob_factory, | 1065 |
665 X_MB_img_ldr | 1066 static void |
666 }; | 1067 _x_supp_reg_IO_factory(mb_IO_factory_t *io_factory) { |
667 /*! \defgroup x_supp_nodejs_sup Export functions for supporting nodejs plugin. | 1068 _io_factory = io_factory; |
668 * | 1069 } |
669 * These functions are for internal using. | 1070 |
670 * @{ | 1071 static void |
671 */ | 1072 _x_supp_reg_timer_factory(mb_timer_factory_t *timer_factory) { |
672 /*! \brief Exported for nodejs plugin to call handle_x_event. | 1073 _timer_factory = timer_factory; |
673 */ | 1074 } |
674 void _X_MB_handle_x_event_for_nodejs(void *rt) { | 1075 |
675 handle_x_event((X_MB_runtime_t *)rt); | 1076 mb_backend_t mb_dfl_backend = { _x_supp_new, |
676 } | 1077 _x_supp_new_with_win, |
677 | 1078 |
678 /*! \brief Get X connect for nodejs plugin. | 1079 _x_supp_free, |
679 */ | 1080 _x_supp_free_keep_win, |
680 int _X_MB_get_x_conn_for_nodejs(void *rt) { | 1081 _x_supp_add_event, |
681 return XConnectionNumber(((X_MB_runtime_t *)rt)->display); | 1082 _x_supp_remove_event, |
682 } | 1083 _x_supp_event_loop, |
683 | 1084 _x_supp_flush, |
684 /*! \brief Flush buffer for the X connection of a runtime object. | 1085 |
685 */ | 1086 _x_supp_kbevents, |
686 int _X_MB_flush_x_conn_for_nodejs(void *rt) { | 1087 _x_supp_rdman, |
687 return XFlush(((X_MB_runtime_t *)rt)->display); | 1088 _x_supp_timer_man, |
688 } | 1089 _x_supp_observer_factory, |
689 | 1090 _x_supp_img_ldr, |
690 /* @} */ | 1091 |
1092 _x_supp_reg_IO_factory, | |
1093 _x_supp_reg_timer_factory, | |
1094 }; |