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