Mercurial > MadButterfly
diff 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 |
line wrap: on
line diff
--- a/src/X_supp.c Mon Jul 19 15:44:49 2010 +0800 +++ b/src/X_supp.c Wed Dec 01 12:25:56 2010 +0800 @@ -1,18 +1,36 @@ +// -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 4; -*- +// vim: sw=4:ts=8:sts=4 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <X11/Xlib.h> #include <X11/Xutil.h> +#include <cairo-xlib.h> #include "mb_graph_engine.h" #include "mb_redraw_man.h" #include "mb_timer.h" #include "mb_X_supp.h" +#include "mb_backend.h" +#include "mb_backend_utils.h" +#include "config.h" + +#ifdef XSHM +/* \sa http://www.xfree86.org/current/mit-shm.html */ +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/extensions/XShm.h> +static void XSHM_update(X_supp_runtime_t *xmb_rt); +#endif #define ERR -1 #define OK 0 +#define ASSERT(x) + #define ONLY_MOUSE_MOVE_RAW 1 +static mb_timer_factory_t *_timer_factory = &tman_timer_factory; + /*! \ingroup xkb * @{ */ @@ -21,18 +39,12 @@ int ksym_per_code; KeySym *syms; subject_t *kbevents; - ob_factory_t *ob_factory; + observer_factory_t *observer_factory; }; /* @} */ -#define MAX_MONITORS 200 -typedef struct { - int type; - int fd; - mb_eventcb_t f; - void *arg; -} monitor_t; -struct _X_MB_runtime { + +struct _X_supp_runtime { Display *display; Window win; Visual *visual; @@ -40,20 +52,221 @@ mbe_pattern_t *surface_ptn; mbe_t *cr, *backend_cr; redraw_man_t *rdman; - mb_tman_t *tman; mb_img_ldr_t *img_ldr; int w, h; X_kb_info_t kbinfo; - monitor_t monitors[MAX_MONITORS]; - int n_monitor; + mb_IO_man_t *io_man; + mb_timer_man_t *timer_man; #ifndef ONLY_MOUSE_MOVE_RAW /* States */ shape_t *last; #endif + +#ifdef XSHM + XImage *ximage; + XShmSegmentInfo shminfo; +#endif + + /* For handle connection */ + int io_hdl; + + /* + * Following variables are used by handle_single_x_event() + */ + int last_evt_type; /* Type of last event */ + int eflag; + int ex1, ey1, ex2, ey2; /* Aggregate expose events */ + int mflag; + int mx, my; /* Position of last motion event */ + int mbut_state; /* Button state of last motion event */ }; +static void _x_supp_handle_x_event(X_supp_runtime_t *rt); + +/*! \defgroup x_supp_io IO manager for X. + * @{ + */ +#define MAX_MONITORS 200 + +typedef struct { + int type; + int fd; + mb_IO_cb_t cb; + void *data; +} monitor_t; + +struct _X_supp_IO_man { + mb_IO_man_t io_man; + monitor_t monitors[MAX_MONITORS]; + int n_monitor; +}; + +static int _x_supp_io_man_reg(struct _mb_IO_man *io_man, + int fd, MB_IO_TYPE type, + mb_IO_cb_t cb, void *data); +static void _x_supp_io_man_unreg(struct _mb_IO_man *io_man, int io_hdl); +static mb_IO_man_t *_x_supp_io_man_new(void); +static void _x_supp_io_man_free(mb_IO_man_t *io_man); + +static mb_IO_factory_t _X_supp_default_io_factory = { + _x_supp_io_man_new, + _x_supp_io_man_free +}; +static mb_IO_factory_t *_io_factory = &_X_supp_default_io_factory; + +static struct _X_supp_IO_man _default_io_man = { + {_x_supp_io_man_reg, _x_supp_io_man_unreg}, + {}, /* monitors */ + 0 /* n_monitor */ +}; + +static mb_IO_man_t * +_x_supp_io_man_new(void) { + return (mb_IO_man_t *)&_default_io_man; +} + +static void +_x_supp_io_man_free(mb_IO_man_t *io_man) { +} + +static int +_x_supp_io_man_reg(struct _mb_IO_man *io_man, + int fd, MB_IO_TYPE type, mb_IO_cb_t cb, void *data) { + struct _X_supp_IO_man *xmb_io_man = (struct _X_supp_IO_man *)io_man; + int i; + + for(i = 0; i < xmb_io_man->n_monitor; i++) { + if (xmb_io_man->monitors[i].type == MB_IO_DUMMY) + break; + } + if (i == MAX_MONITORS) + return ERR; + + xmb_io_man->monitors[i].type = type; + xmb_io_man->monitors[i].fd = fd; + xmb_io_man->monitors[i].cb = cb; + xmb_io_man->monitors[i].data = data; + i++; + if(i > xmb_io_man->n_monitor) + xmb_io_man->n_monitor = i; + return i - 1; +} + +static void +_x_supp_io_man_unreg(struct _mb_IO_man *io_man, int io_hdl) { + struct _X_supp_IO_man *xmb_io_man = (struct _X_supp_IO_man *)io_man; + + ASSERT(io_hdl < xmb_io_man->n_monitor); + xmb_io_man->monitors[io_hdl].type = MB_IO_DUMMY; +} + +/*! \brief Handle connection coming data and timeout of timers. + * + * \param display is a Display returned by XOpenDisplay(). + * \param rdman is a redraw manager. + * \param tman is a timer manager. + * + * The display is managed by specified rdman and tman. rdman draws + * on the display, and tman trigger actions according timers. + */ +static void +_x_supp_event_loop(mb_rt_t *rt) { + struct _X_supp_runtime *xmb_rt = (struct _X_supp_runtime *)rt; + struct _X_supp_IO_man *io_man = (struct _X_supp_IO_man *)xmb_rt->io_man; + mb_timer_man_t *timer_man = (mb_timer_man_t *)xmb_rt->timer_man; + redraw_man_t *rdman; + mb_tman_t *tman = tman_timer_man_get_tman(timer_man); + mb_timeval_t now, tmo; + struct timeval tv; + fd_set rfds, wfds; + int nfds = 0; + int r, r1,i; + + rdman = mb_runtime_rdman(rt); + + _x_supp_handle_x_event(xmb_rt); + + while(1) { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + for(i = 0; i < io_man->n_monitor; i++) { + if(io_man->monitors[i].type == MB_IO_R || + io_man->monitors[i].type == MB_IO_RW) { + FD_SET(io_man->monitors[i].fd, &rfds); + nfds = MB_MAX(nfds, io_man->monitors[i].fd + 1); + } + if(io_man->monitors[i].type == MB_IO_W || + io_man->monitors[i].type == MB_IO_RW) { + FD_SET(io_man->monitors[i].fd, &wfds); + nfds = MB_MAX(nfds, io_man->monitors[i].fd + 1); + } + } + + get_now(&now); + r = mb_tman_next_timeout(tman, &now, &tmo); + + if(r == 0) { + tv.tv_sec = MB_TIMEVAL_SEC(&tmo); + tv.tv_usec = MB_TIMEVAL_USEC(&tmo); + r1 = select(nfds, &rfds, NULL, NULL, &tv); + } else + r1 = select(nfds, &rfds, NULL, NULL, NULL); + + if(r1 == -1) { + perror("select"); + break; + } + + if(r1 == 0) { + get_now(&now); + mb_tman_handle_timeout(tman, &now); + rdman_redraw_changed(rdman); +#ifdef XSHM + XSHM_update(xmb_rt); +#endif + XFlush(xmb_rt->display); + } else { + for(i = 0; i < io_man->n_monitor; i++) { + if(io_man->monitors[i].type == MB_IO_R || + io_man->monitors[i].type == MB_IO_RW) { + if(FD_ISSET(io_man->monitors[i].fd, &rfds)) + io_man->monitors[i].cb(i, io_man->monitors[i].fd, + MB_IO_R, + io_man->monitors[i].data); + } + if(io_man->monitors[i].type == MB_IO_W || + io_man->monitors[i].type == MB_IO_RW) { + if(FD_ISSET(io_man->monitors[i].fd, &wfds)) + io_man->monitors[i].cb(i, io_man->monitors[i].fd, + MB_IO_W, + io_man->monitors[i].data); + } + } + } + } +} + +/* @} */ + +#ifdef XSHM +static void +XSHM_update(X_supp_runtime_t *xmb_rt) { + GC gc; + + gc = DefaultGC(xmb_rt->display, DefaultScreen(xmb_rt->display)); + if(xmb_rt->ximage) { /* support XSHM */ + XShmPutImage(xmb_rt->display, + xmb_rt->win, + gc, + xmb_rt->ximage, + 0, 0, 0, 0, + xmb_rt->w, xmb_rt->h, 0); + } +} +#endif + /*! \defgroup xkb X Keyboard Handling * * Accept keyboard events from X server and delivery it to @@ -73,7 +286,7 @@ static int X_kb_init(X_kb_info_t *kbinfo, Display *display, redraw_man_t *rdman) { int n_syms; - ob_factory_t *factory; + observer_factory_t *factory; int r; r = XDisplayKeycodes(display, @@ -89,12 +302,12 @@ if(kbinfo->syms == NULL) return ERR; - factory = rdman_get_ob_factory(rdman); + factory = rdman_get_observer_factory(rdman); kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB); if(kbinfo->kbevents == NULL) return ERR; - /*! \todo Make sure ob_factory is still need. */ - kbinfo->ob_factory = factory; + /*! \todo Make sure observer_factory is still need. */ + kbinfo->observer_factory = factory; return OK; } @@ -104,7 +317,8 @@ XFree(kbinfo->syms); } -/*! \brief Accept X keyboard events from handle_x_event() and dispatch it. +/*! \brief Accept X keyboard events from _x_supp_handle_x_event() and + * dispatch it. */ static void X_kb_handle_event(X_kb_info_t *kbinfo, XKeyEvent *xkey) { unsigned int code; @@ -123,7 +337,6 @@ subject_notify(kbinfo->kbevents, &event.event); } - /* @} */ static unsigned int get_button_state(unsigned int state) { @@ -135,7 +348,7 @@ but |= MOUSE_BUT2; if(state & Button3Mask) but |= MOUSE_BUT3; - + return but; } @@ -171,35 +384,193 @@ mouse_event.y = y; mouse_event.but_state = state; mouse_event.button = button; - + if(IS_MBO_SHAPES(obj)) subject = sh_get_mouse_event_subject((shape_t *)obj); else subject = coord_get_mouse_event((coord_t *)obj); + + subject_notify(subject, (event_t *)&mouse_event); +} + +/*! \brief Handle motion event. + */ +static void +handle_motion_event(X_supp_runtime_t *rt) { + redraw_man_t *rdman = rt->rdman; + int x, y; + int state; + shape_t *shape; + coord_t *root; + int in_stroke; - subject_notify(subject, (event_t *)&mouse_event); + x = rt->mx; + y = rt->my; + state = rt->mbut_state; + + shape = find_shape_at_pos(rdman, x, y, + &in_stroke); +#ifdef ONLY_MOUSE_MOVE_RAW + if(shape != NULL) { + notify_coord_or_shape(rdman, (mb_obj_t *)shape, + x, y, EVT_MOUSE_MOVE_RAW, state, 0); + } else { + root = rdman_get_root(rdman); + notify_coord_or_shape(rdman, (mb_obj_t *)root, + x, y, EVT_MOUSE_MOVE_RAW, state, 0); + } +#else + if(shape != NULL) { + if(rt->last != shape) { + if(rt->last) + notify_coord_or_shape(rdman, rt->last, x, y, + EVT_MOUSE_OUT, state, 0); + notify_coord_or_shape(rdman, shape, x, y, + EVT_MOUSE_OVER, state, 0); + rt->last = shape; + } else + notify_coord_or_shape(rdman, shape, x, y, + EVT_MOUSE_MOVE, state, 0); + } else { + if(rt->last) { + notify_coord_or_shape(rdman, rt->last, x, y, + EVT_MOUSE_OUT, state, 0); + rt->last = NULL; + } + } +#endif + + rt->mflag = 0; +} + +/*! \brief Redraw exposed area. + */ +static void +handle_expose_event(X_supp_runtime_t *rt) { + redraw_man_t *rdman = rt->rdman; + int ex1, ey1, ex2, ey2; + + ex1 = rt->ex1; + ey1 = rt->ey1; + ex2 = rt->ex2; + ey2 = rt->ey2; + + rdman_redraw_area(rdman, ex1, ey1, (ex2 - ex1), (ey2 - ey1)); + + rt->eflag = 0; +} + +/*! \brief Handle single X event and maintain internal states. + * + * It keeps internal state in rt to improve performance. + */ +static void +handle_single_x_event(X_supp_runtime_t *rt, XEvent *evt) { + redraw_man_t *rdman = rt->rdman; + XMotionEvent *mevt; + XButtonEvent *bevt; + XExposeEvent *eevt; + XKeyEvent *xkey; + int x, y, w, h; + + shape_t *shape; + + unsigned int state, button; + int in_stroke; + + if(evt->type != MotionNotify && rt->mflag) + handle_motion_event(rt); + + switch(evt->type) { + case ButtonPress: + bevt = (XButtonEvent *)evt; + x = bevt->x; + y = bevt->y; + state = get_button_state(bevt->state); + button = get_button(bevt->button); + + shape = find_shape_at_pos(rdman, x, y, + &in_stroke); + if(shape) + notify_coord_or_shape(rdman, (mb_obj_t *)shape, + x, y, EVT_MOUSE_BUT_PRESS, + state, button); + break; + + case ButtonRelease: + bevt = (XButtonEvent *)evt; + x = bevt->x; + y = bevt->y; + state = get_button_state(bevt->state); + button = get_button(bevt->button); + + shape = find_shape_at_pos(rdman, x, y, + &in_stroke); + if(shape) + notify_coord_or_shape(rdman, (mb_obj_t *)shape, + x, y, EVT_MOUSE_BUT_RELEASE, + state, button); + break; + + case MotionNotify: + mevt = (XMotionEvent *)evt; + rt->mx = mevt->x; + rt->my = mevt->y; + rt->mbut_state = get_button_state(mevt->state); + rt->mflag = 1; + break; + + case KeyPress: + case KeyRelease: + xkey = &evt->xkey; + X_kb_handle_event(&rt->kbinfo, xkey); + break; + + case Expose: + eevt = &evt->xexpose; + x = eevt->x; + y = eevt->y; + w = eevt->width; + h = eevt->height; + + if(rt->eflag) { + if(x < rt->ex1) + rt->ex1 = x; + if(y < rt->ey1) + rt->ey1 = y; + if((x + w) > rt->ex2) + rt->ex2 = x + w; + if((y + h) > rt->ey2) + rt->ey2 = y + h; + } else { + rt->ex1 = x; + rt->ey1 = y; + rt->ex2 = x + w; + rt->ey2 = y + h; + rt->eflag = 1; + } + break; + } +} + +/*! \brief Call when no more event in an event iteration. + * + * No more event means event queue is emplty. This function will + * perform some actions according current internal state. + */ +static void +no_more_event(X_supp_runtime_t *rt) { + if(rt->mflag) + handle_motion_event(rt); + if(rt->eflag) + handle_expose_event(rt); } /*! \brief Dispatch all X events in the queue. */ -static void handle_x_event(X_MB_runtime_t *rt) { +static void _x_supp_handle_x_event(X_supp_runtime_t *rt) { Display *display = rt->display; - redraw_man_t *rdman = rt->rdman; - XEvent evt, peek_evt; - XMotionEvent *mevt; - XButtonEvent *bevt; - XExposeEvent *eevt; - XKeyEvent *xkey; - co_aix x, y, w, h; - - int eflag = 0; - int ex1=0, ey1=0, ex2=0, ey2=0; - - shape_t *shape; - coord_t *root; - - unsigned int state, button; - int in_stroke; + XEvent evt; int r; /* XXX: For some unknown reason, it causes a segmentation fault to @@ -211,200 +582,23 @@ if(r == -1) break; - switch(evt.type) { - case ButtonPress: - bevt = (XButtonEvent *)&evt; - x = bevt->x; - y = bevt->y; - state = get_button_state(bevt->state); - button = get_button(bevt->button); - - shape = find_shape_at_pos(rdman, x, y, - &in_stroke); - if(shape) - notify_coord_or_shape(rdman, (mb_obj_t *)shape, - x, y, EVT_MOUSE_BUT_PRESS, - state, button); - break; - - case ButtonRelease: - bevt = (XButtonEvent *)&evt; - x = bevt->x; - y = bevt->y; - state = get_button_state(bevt->state); - button = get_button(bevt->button); - - shape = find_shape_at_pos(rdman, x, y, - &in_stroke); - if(shape) - notify_coord_or_shape(rdman, (mb_obj_t *)shape, - x, y, EVT_MOUSE_BUT_RELEASE, - state, button); - break; - - case MotionNotify: - while(XEventsQueued(display, QueuedAfterReading) > 0) { - r = XPeekEvent(display, &peek_evt); - if(r == -1) - break; - if(peek_evt.type != MotionNotify) - break; - XNextEvent(display, &evt); - } - if(r == -1) - break; - - mevt = (XMotionEvent *)&evt; - x = mevt->x; - y = mevt->y; - state = get_button_state(mevt->state); - - shape = find_shape_at_pos(rdman, x, y, - &in_stroke); -#ifdef ONLY_MOUSE_MOVE_RAW - if(shape != NULL) { - notify_coord_or_shape(rdman, (mb_obj_t *)shape, - x, y, EVT_MOUSE_MOVE_RAW, state, 0); - } else { - root = rdman_get_root(rdman); - notify_coord_or_shape(rdman, (mb_obj_t *)root, - x, y, EVT_MOUSE_MOVE_RAW, state, 0); - } -#else - if(shape != NULL) { - if(rt->last != shape) { - if(rt->last) - notify_coord_or_shape(rdman, rt->last, x, y, - EVT_MOUSE_OUT, state, 0); - notify_coord_or_shape(rdman, shape, x, y, - EVT_MOUSE_OVER, state, 0); - rt->last = shape; - } else - notify_coord_or_shape(rdman, shape, x, y, - EVT_MOUSE_MOVE, state, 0); - } else { - if(rt->last) { - notify_coord_or_shape(rdman, rt->last, x, y, - EVT_MOUSE_OUT, state, 0); - rt->last = NULL; - } - } + handle_single_x_event(rt, &evt); + } + no_more_event(rt); + +#ifdef XSHM + XSHM_update(rt); #endif - break; - - case KeyPress: - case KeyRelease: - xkey = &evt.xkey; - X_kb_handle_event(&rt->kbinfo, xkey); - break; - - case Expose: - eevt = &evt.xexpose; - x = eevt->x; - y = eevt->y; - w = eevt->width; - h = eevt->height; - - if(eflag) { - if(x < ex1) - ex1 = x; - if(y < ey1) - ey1 = y; - if((x + w) > ex2) - ex2 = x + w; - if((y + h) > ey2) - ey2 = y + h; - } else { - ex1 = x; - ey1 = y; - ex2 = x + w; - ey2 = y + h; - eflag = 1; - } - break; - } - } - if(eflag) { - rdman_redraw_area(rdman, ex1, ey1, (ex2 - ex1), (ey2 - ey1)); - eflag = 0; - } XFlush(display); } -/*! \brief Handle connection coming data and timeout of timers. - * - * \param display is a Display returned by XOpenDisplay(). - * \param rdman is a redraw manager. - * \param tman is a timer manager. - * - * The display is managed by specified rdman and tman. rdman draws - * on the display, and tman trigger actions according timers. - */ -void X_MB_handle_connection(void *be) { - X_MB_runtime_t *rt = (X_MB_runtime_t *) be; - Display *display = rt->display; - redraw_man_t *rdman = rt->rdman; - mb_tman_t *tman = rt->tman; - int fd; - mb_timeval_t now, tmo; - struct timeval tv; - fd_set rfds,wfds; - int nfds; - int r, r1,i; - - handle_x_event(rt); +static void +_x_supp_handle_connection(int hdl, int fd, MB_IO_TYPE type, void *data) { + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *)data; - fd = XConnectionNumber(display); - nfds = fd + 1; - while(1) { - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_SET(fd, &rfds); - for(i=0;i<rt->n_monitor;i++) { - if (rt->monitors[i].type == MONITOR_READ) - FD_SET(rt->monitors[i].fd, &rfds); - else if (rt->monitors[i].type == MONITOR_WRITE) - FD_SET(rt->monitors[i].fd, &wfds); - } - - get_now(&now); - r = mb_tman_next_timeout(tman, &now, &tmo); - - if(r == 0) { - tv.tv_sec = MB_TIMEVAL_SEC(&tmo); - tv.tv_usec = MB_TIMEVAL_USEC(&tmo); - r1 = select(nfds, &rfds, NULL, NULL, &tv); - } else - r1 = select(nfds, &rfds, NULL, NULL, NULL); - - if(r1 == -1) { - perror("select"); - break; - } - - if(r1 == 0) { - get_now(&now); - mb_tman_handle_timeout(tman, &now); - rdman_redraw_changed(rdman); - XFlush(display); - } else if(FD_ISSET(fd, &rfds)){ - handle_x_event(rt); - } else { - for(i=0;i<rt->n_monitor;i++) { - if (rt->monitors[i].type == MONITOR_READ) - if (FD_ISSET(rt->monitors[i].fd, &rfds)) - rt->monitors[i].f(rt->monitors[i].fd,rt->monitors[i].arg); - else if (rt->monitors[i].type == MONITOR_WRITE) - if (FD_ISSET(rt->monitors[i].fd, &wfds)) - rt->monitors[i].f(rt->monitors[i].fd,rt->monitors[i].arg); - } - } - } + _x_supp_handle_x_event(xmb_rt); } -#define ERR -1 -#define OK 0 - static int X_init_connection(const char *display_name, int w, int h, Display **displayp, @@ -417,9 +611,27 @@ XSetWindowAttributes wattr; int depth; int x, y; + int draw_root = 0; + const char *disp_name; + char disp_buf[32]; + int cp; int r; - display = XOpenDisplay(display_name); + /* + * Support drawing on the root window. + */ + disp_name = display_name; + if(strstr(display_name, ":root") != NULL) { + draw_root = 1; + cp = strlen(display_name) - 5; + if(cp >= 32) + cp = 31; + memcpy(disp_buf, display_name, cp); + disp_buf[cp] = 0; + disp_name = disp_buf; + } + + display = XOpenDisplay(disp_name); if(display == NULL) return ERR; @@ -430,15 +642,19 @@ wattr.override_redirect = False; x = 10; y = 10; - win = XCreateWindow(display, root, - x, y, - w, h, - 1, depth, InputOutput, visual, - CWOverrideRedirect, &wattr); - r = XMapWindow(display, win); - if(r == -1) { - XCloseDisplay(display); - return ERR; + if(draw_root) + win = RootWindowOfScreen(ScreenOfDisplay(display, screen)); + else { + win = XCreateWindow(display, root, + x, y, + w, h, + 1, depth, InputOutput, visual, + CWOverrideRedirect, &wattr); + r = XMapWindow(display, win); + if(r == -1) { + XCloseDisplay(display); + return ERR; + } } XSelectInput(display, win, PointerMotionMask | ExposureMask | @@ -453,89 +669,231 @@ return OK; } +#ifdef XSHM +static void +xshm_destroy(X_supp_runtime_t *xmb_rt) { + XShmSegmentInfo *shminfo; + + shminfo = &xmb_rt->shminfo; + + if(xmb_rt->shminfo.shmaddr) { + XShmDetach(xmb_rt->display, shminfo); + } + + if(xmb_rt->ximage) { + XDestroyImage(xmb_rt->ximage); + xmb_rt->ximage = NULL; + } + + if(shminfo->shmaddr) { + shmdt(shminfo->shmaddr); + shminfo->shmaddr = NULL; + } + + if(shminfo->shmid) { + shmctl(shminfo->shmid, IPC_RMID, 0); + shminfo->shmid = 0; + } +} + +static void +xshm_init(X_supp_runtime_t *xmb_rt) { + Display *display; + Visual *visual; + XImage *ximage; + int screen; + int depth; + int support_shm; + int mem_sz; + XShmSegmentInfo *shminfo; + int surf_fmt; + + display = xmb_rt->display; + visual = xmb_rt->visual; + shminfo = &xmb_rt->shminfo; + + support_shm = XShmQueryExtension(display); + if(!support_shm) + return; + + screen = DefaultScreen(display); + depth = DefaultDepth(display, screen); + + if(depth != 24 && depth != 32) + return; + + xmb_rt->ximage = XShmCreateImage(display, visual, depth, + ZPixmap, NULL, shminfo, + xmb_rt->w, xmb_rt->h); + ximage = xmb_rt->ximage; + + mem_sz = ximage->bytes_per_line * ximage->height; + shminfo->shmid = shmget(IPC_PRIVATE, mem_sz, IPC_CREAT | 0777); + if(shminfo->shmid == -1) { + xshm_destroy(xmb_rt); + return; + } + + shminfo->shmaddr = shmat(shminfo->shmid, 0, 0); + ximage->data = shminfo->shmaddr; + + shminfo->readOnly = 0; + + XShmAttach(display, shminfo); + + switch(depth) { + case 24: surf_fmt = CAIRO_FORMAT_RGB24; break; + case 32: surf_fmt = CAIRO_FORMAT_ARGB32; break; + } + + xmb_rt->backend_surface = + mbe_image_surface_create_for_data((unsigned char *)ximage->data, + surf_fmt, + xmb_rt->w, + xmb_rt->h, + ximage->bytes_per_line); + if(xmb_rt->backend_surface == NULL) + xshm_destroy(xmb_rt); +} +#endif /* XSHM */ + /*! \brief Initialize a MadButterfy runtime for Xlib. * - * It setups a runtime environment to run MadButterfly with Xlib. - * Users should specify width and height of the opening window. + * This one is very like _x_supp_init(), except it accepts a + * X_supp_runtime_t object initialized with a display connected to a X + * server and an opened window. + * + * Following field of the X_supp_runtime_t object should be initialized. + * - w, h + * - win + * - display + * - visual */ -static int X_MB_init(const char *display_name, - int w, int h, X_MB_runtime_t *xmb_rt) { +static int +_x_supp_init_with_win_internal(X_supp_runtime_t *xmb_rt) { mb_img_ldr_t *img_ldr; - - memset(xmb_rt, 0, sizeof(X_MB_runtime_t)); + int w, h; + int disp_fd; - xmb_rt->w = w; - xmb_rt->h = h; - X_init_connection(display_name, w, h, &xmb_rt->display, - &xmb_rt->visual, &xmb_rt->win); -#ifdef OPENVG_GRAPH_ENGINE - _ge_openvg_disp_id = xmb_rt->display; + w = xmb_rt->w; + h = xmb_rt->h; + +#ifdef XSHM + xshm_init(xmb_rt); #endif - mbe_init(); - xmb_rt->surface = mbe_image_surface_create(MB_IFMT_ARGB32, w, h); xmb_rt->surface_ptn = mbe_pattern_create_for_surface(xmb_rt->surface); - -#ifdef OPENVG_GRAPH_ENGINE - xmb_rt->backend_surface = - mbe_vg_win_surface_create(xmb_rt->display, - xmb_rt->win, - xmb_rt->visual, - w, h); -#else - xmb_rt->backend_surface = - mbe_xlib_surface_create(xmb_rt->display, - xmb_rt->win, - xmb_rt->visual, - w, h); -#endif + + if(xmb_rt->backend_surface == NULL) /* xshm_init() may create one */ + xmb_rt->backend_surface = + mbe_xlib_surface_create(xmb_rt->display, + xmb_rt->win, + xmb_rt->visual, + w, h); xmb_rt->cr = mbe_create(xmb_rt->surface); xmb_rt->backend_cr = mbe_create(xmb_rt->backend_surface); - /* TODO: Remove this line. Since we use mbe_copy_source(), it - * will set source for the backend. So, this line is redundants. - * It can be removed. sourface_ptn can be removed, too. - */ mbe_set_source(xmb_rt->backend_cr, xmb_rt->surface_ptn); xmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t)); redraw_man_init(xmb_rt->rdman, xmb_rt->cr, xmb_rt->backend_cr); - // FIXME: This is a wired loopback reference. This is inly required when we need + // FIXME: This is a wired loopback reference. This is inly required when we need // to get the xmb_rt->tman for the animation. We should relocate the tman // to the redraw_man_t instead. xmb_rt->rdman->rt = xmb_rt; - xmb_rt->rdman->w = w; - xmb_rt->rdman->h = h; - xmb_rt->tman = mb_tman_new(); + xmb_rt->io_man = mb_io_man_new(_io_factory); + xmb_rt->timer_man = mb_timer_man_new(_timer_factory); img_ldr = simple_mb_img_ldr_new(""); xmb_rt->img_ldr = img_ldr; - rdman_set_img_ldr(xmb_rt->rdman, img_ldr); - memset(xmb_rt->monitors,0,sizeof(xmb_rt->monitors)); - + /*! \todo Remove rdman_set_img_ldr() */ + rdman_set_img_ldr(xmb_rt->rdman, img_ldr); /* this is ncessary? */ + #ifndef ONLY_MOUSE_MOVE_RAW xmb_rt->last = NULL; #endif X_kb_init(&xmb_rt->kbinfo, xmb_rt->display, xmb_rt->rdman); + disp_fd = XConnectionNumber(xmb_rt->display); + xmb_rt->io_hdl = mb_io_man_reg(xmb_rt->io_man, disp_fd, + MB_IO_R, + _x_supp_handle_connection, + xmb_rt); + return OK; } -static void X_MB_destroy(X_MB_runtime_t *xmb_rt) { +/*! \brief Initialize a MadButterfy runtime for Xlib. + * + * It setups a runtime environment to run MadButterfly with Xlib. + * Users should specify width and height of the opening window. + */ +static int _x_supp_init(X_supp_runtime_t *xmb_rt, const char *display_name, + int w, int h) { + int r; + + memset(xmb_rt, 0, sizeof(X_supp_runtime_t)); + + xmb_rt->w = w; + xmb_rt->h = h; + r = X_init_connection(display_name, w, h, &xmb_rt->display, + &xmb_rt->visual, &xmb_rt->win); + if(r != OK) + return ERR; + + r = _x_supp_init_with_win_internal(xmb_rt); + + return r; +} + +/*! \brief Initialize a MadButterfly runtime for a window of X. + * + * Runtimes initialized with this function should be destroyed with + * x_supp_destroy_keep_win(). + */ +static int +_x_supp_init_with_win(X_supp_runtime_t *xmb_rt, + Display *display, Window win) { + XWindowAttributes attrs; + int r; + + r = XGetWindowAttributes(display, win, &attrs); + if(r == 0) + return ERR; + + memset(xmb_rt, 0, sizeof(X_supp_runtime_t)); + + xmb_rt->display = display; + xmb_rt->win = win; + xmb_rt->visual = attrs.visual; + xmb_rt->w = attrs.width; + xmb_rt->h = attrs.height; + + r = _x_supp_init_with_win_internal(xmb_rt); + + return r; +} + +static void x_supp_destroy(X_supp_runtime_t *xmb_rt) { if(xmb_rt->rdman) { redraw_man_destroy(xmb_rt->rdman); free(xmb_rt->rdman); } - if(xmb_rt->tman) - mb_tman_free(xmb_rt->tman); + if(xmb_rt->io_hdl) + mb_io_man_unreg(xmb_rt->io_man, xmb_rt->io_hdl); + + if(xmb_rt->io_man) + mb_io_man_free(_io_factory, xmb_rt->io_man); + if(xmb_rt->timer_man) + mb_timer_man_free(_timer_factory, xmb_rt->timer_man); if(xmb_rt->img_ldr) MB_IMG_LDR_FREE(xmb_rt->img_ldr); @@ -558,133 +916,179 @@ X_kb_destroy(&xmb_rt->kbinfo); } -void *X_MB_new(const char *display_name, int w, int h) { - X_MB_runtime_t *rt; +/*! \brief Destroy a MadButterfly runtime initialized with + * _x_supp_init_with_win(). + * + * Destroying a runtime with this function prevent the window and + * display associated with the runtime being closed. + */ +static void +x_supp_destroy_keep_win(X_supp_runtime_t *xmb_rt) { + Display *display; + Window win; + + display = xmb_rt->display; + xmb_rt->display = NULL; + win = xmb_rt->win; + xmb_rt->win = 0; + + x_supp_destroy(xmb_rt); + + xmb_rt->display = display; + xmb_rt->win = win; +} + +static mb_rt_t * +_x_supp_new(const char *display_name, int w, int h) { + X_supp_runtime_t *rt; int r; - rt = O_ALLOC(X_MB_runtime_t); + rt = O_ALLOC(X_supp_runtime_t); if(rt == NULL) return NULL; - r = X_MB_init(display_name, w, h, rt); + r = _x_supp_init(rt, display_name, w, h); if(r != OK) { free(rt); return NULL; } - return rt; + return (mb_rt_t *)rt; } -void X_MB_free(void *rt) { - X_MB_destroy((X_MB_runtime_t *) rt); +/*! \brief Create a new runtime for existed window for X. + * + * The object returned by this function must be free with + * _x_supp_free_keep_win() to prevent the window from closed. + */ +static mb_rt_t * +_x_supp_new_with_win(MB_DISPLAY display, MB_WINDOW win) { + X_supp_runtime_t *rt; + int r; + + rt = O_ALLOC(X_supp_runtime_t); + if(rt == NULL) + return NULL; + + r = _x_supp_init_with_win(rt, display, win); + if(r != OK) { + free(rt); + return NULL; + } + + return (mb_rt_t *)rt; +} + +static void +_x_supp_free(mb_rt_t *rt) { + x_supp_destroy((X_supp_runtime_t *) rt); free(rt); } -subject_t *X_MB_kbevents(void *rt) { - X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; +/*! \brief Free runtime created with _x_supp_new_with_win(). + */ +static void +_x_supp_free_keep_win(mb_rt_t *rt) { + x_supp_destroy_keep_win((X_supp_runtime_t *) rt); + free(rt); +} + +static subject_t * +_x_supp_kbevents(mb_rt_t *rt) { + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; return xmb_rt->kbinfo.kbevents; } -redraw_man_t *X_MB_rdman(void *rt) { - X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; +static redraw_man_t * +_x_supp_rdman(mb_rt_t *rt) { + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; return xmb_rt->rdman; } -mb_tman_t *X_MB_tman(void *rt) { - X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; - return xmb_rt->tman; +static mb_timer_man_t * +_x_supp_timer_man(mb_rt_t *rt) { + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; + return xmb_rt->timer_man; } -ob_factory_t *X_MB_ob_factory(void *rt) { - X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; - ob_factory_t *factory; +static observer_factory_t * +_x_supp_observer_factory(mb_rt_t *rt) { + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; + observer_factory_t *factory; - factory = rdman_get_ob_factory(xmb_rt->rdman); + factory = rdman_get_observer_factory(xmb_rt->rdman); return factory; } -mb_img_ldr_t *X_MB_img_ldr(void *rt) { - X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; - X_MB_runtime_t *img_ldr; +static mb_img_ldr_t * +_x_supp_img_ldr(mb_rt_t *rt) { + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; + mb_img_ldr_t *img_ldr; img_ldr = xmb_rt->img_ldr; return img_ldr; } -void X_MB_add_event(void *rt, int type, int fd, mb_eventcb_t f,void *arg) +static int +_x_supp_add_event(mb_rt_t *rt, int fd, MB_IO_TYPE type, + mb_IO_cb_t cb, void *data) { - X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; - int i; + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; + mb_IO_man_t *io_man = xmb_rt->io_man; + int hdl; - for(i=0;i<xmb_rt->n_monitor;i++) { - if (xmb_rt->monitors[i].type == type && xmb_rt->monitors[i].fd == fd) { - xmb_rt->monitors[i].f = f; - xmb_rt->monitors[i].arg = arg; - return; - } - } - for(i=0;i<xmb_rt->n_monitor;i++) { - if (xmb_rt->monitors[i].type == 0) { - xmb_rt->monitors[i].type = type; - xmb_rt->monitors[i].fd = fd; - xmb_rt->monitors[i].f = f; - xmb_rt->monitors[i].arg = arg; - return; - } - } - if (i == MAX_MONITORS) return; - xmb_rt->monitors[i].type = type; - xmb_rt->monitors[i].fd = fd; - xmb_rt->monitors[i].f = f; - xmb_rt->monitors[i].arg = arg; - i++; - xmb_rt->n_monitor=i; + hdl = mb_io_man_reg(io_man, fd, type, cb, data); + return hdl; +} + +static void +_x_supp_remove_event(mb_rt_t *rt, int hdl) +{ + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; + mb_IO_man_t *io_man = xmb_rt->io_man; + + mb_io_man_unreg(io_man, hdl); } -void X_MB_remove_event(void *rt, int type, int fd) -{ - X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt; - int i; - for(i=0;i<xmb_rt->n_monitor;i++) { - if (xmb_rt->monitors[i].type == type && xmb_rt->monitors[i].fd == fd) { - xmb_rt->monitors[i].type = 0; - return; - } - } +static int +_x_supp_flush(mb_rt_t *rt) { + X_supp_runtime_t *xmb_rt = (X_supp_runtime_t *) rt; + int r; + +#ifdef XSHM + XSHM_update(xmb_rt); +#endif + r = XFlush(xmb_rt->display); + return r == 0? ERR: OK; } -mb_backend_t backend = { X_MB_new, - X_MB_free, - X_MB_add_event, - X_MB_remove_event, - X_MB_handle_connection, - X_MB_kbevents, - X_MB_rdman, - X_MB_tman, - X_MB_ob_factory, - X_MB_img_ldr - }; -/*! \defgroup x_supp_nodejs_sup Export functions for supporting nodejs plugin. - * - * These functions are for internal using. - * @{ - */ -/*! \brief Exported for nodejs plugin to call handle_x_event. - */ -void _X_MB_handle_x_event_for_nodejs(void *rt) { - handle_x_event((X_MB_runtime_t *)rt); + +static void +_x_supp_reg_IO_factory(mb_IO_factory_t *io_factory) { + _io_factory = io_factory; } -/*! \brief Get X connect for nodejs plugin. - */ -int _X_MB_get_x_conn_for_nodejs(void *rt) { - return XConnectionNumber(((X_MB_runtime_t *)rt)->display); +static void +_x_supp_reg_timer_factory(mb_timer_factory_t *timer_factory) { + _timer_factory = timer_factory; } -/*! \brief Flush buffer for the X connection of a runtime object. - */ -int _X_MB_flush_x_conn_for_nodejs(void *rt) { - return XFlush(((X_MB_runtime_t *)rt)->display); -} +mb_backend_t mb_dfl_backend = { _x_supp_new, + _x_supp_new_with_win, + + _x_supp_free, + _x_supp_free_keep_win, + _x_supp_add_event, + _x_supp_remove_event, + _x_supp_event_loop, + _x_supp_flush, + + _x_supp_kbevents, + _x_supp_rdman, + _x_supp_timer_man, + _x_supp_observer_factory, + _x_supp_img_ldr, -/* @} */ + _x_supp_reg_IO_factory, + _x_supp_reg_timer_factory, +};