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 /* @} */