Mercurial > MadButterfly
diff src/X_supp.c @ 78:3645e29e4986
Add runtime for Xlib.
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Wed, 20 Aug 2008 23:33:04 +0800 |
parents | a6763f080da5 |
children | 13fdf205047b |
line wrap: on
line diff
--- a/src/X_supp.c Wed Aug 20 00:32:11 2008 +0800 +++ b/src/X_supp.c Wed Aug 20 23:33:04 2008 +0800 @@ -1,24 +1,83 @@ #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <X11/Xlib.h> #include <X11/Xutil.h> +#include <cairo.h> +#include <cairo-xlib.h> #include "redraw_man.h" #include "mb_timer.h" +#include "X_supp.h" -/*! \brief Dispatch all events in the queue. +static unsigned int get_button_state(unsigned int state) { + unsigned int but = 0; + + if(state & Button1Mask) + but |= MOUSE_BUT1; + if(state & Button2Mask) + but |= MOUSE_BUT2; + if(state & Button3Mask) + but |= MOUSE_BUT3; + + return but; +} + +static unsigned int get_button(unsigned int button) { + switch(button) { + case Button1: + return MOUSE_BUT1; + case Button2: + return MOUSE_BUT2; + case Button3: + return MOUSE_BUT3; + } + return 0; +} + +/*! \brief Notify observers of the shape at specified + * position for mouse event. + * + * Observers of parent shapes may be called if the subject is not + * with SUBF_STOP_PROPAGATE flag. The subject of mouse event + * for a shape is returned by sh_get_mouse_event_subject(). + */ +static void notify_shapes(redraw_man_t *rdman, + co_aix x, co_aix y, int etype, + unsigned int state, + unsigned int button) { + mouse_event_t mouse_event; + shape_t *shape; + subject_t *subject; + ob_factory_t *factory; + int in_stroke; + + mouse_event.event.type = etype; + mouse_event.x = x; + mouse_event.y = y; + mouse_event.but_state = state; + mouse_event.button = button; + + shape = find_shape_at_pos(rdman, x, y, + &in_stroke); + if(shape == NULL) + return; + subject = sh_get_mouse_event_subject(shape); + factory = rdman_get_ob_factory(rdman); + + subject_notify(factory, subject, (event_t *)&mouse_event); +} + +/*! \brief Dispatch all X events in the queue. */ static void handle_x_event(Display *display, redraw_man_t *rdman, mb_tman_t *tman) { XEvent evt; XMotionEvent *mevt; - mouse_event_t mouse_event; - shape_t *shape; - subject_t *subject; - ob_factory_t *factory; + XButtonEvent *bevt; co_aix x, y; - int in_stroke; - int but; + unsigned int state, button; int r; while(XEventsQueued(display, QueuedAfterReading) > 0) { @@ -27,29 +86,35 @@ 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); + + notify_shapes(rdman, 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); + + notify_shapes(rdman, x, y, EVT_MOUSE_BUT_RELEASE, + state, button); + break; + case MotionNotify: mevt = (XMotionEvent *)&evt; x = mevt->x; y = mevt->y; - but = 0; - if(mevt->state & Button1Mask) - but |= MOUSE_BUT1; - if(mevt->state & Button2Mask) - but |= MOUSE_BUT2; - if(mevt->state & Button3Mask) - but |= MOUSE_BUT3; + state = get_button_state(mevt->state); - mouse_event.event.type = EVT_MOUSE_MOVE; - mouse_event.x = x; - mouse_event.y = y; - mouse_event.button = but; - - shape = find_shape_at_pos(rdman, x, y, - &in_stroke); - subject = sh_get_mouse_event_subject(shape); - factory = rdman_get_ob_factory(rdman); - - subject_notify(factory, subject, (event_t *)&mouse_event); + notify_shapes(rdman, x, y, EVT_MOUSE_MOVE, state, 0); break; case Expose: @@ -63,10 +128,17 @@ } /*! \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_handle_connection(Display *display, - redraw_man_t *rdman, - mb_tman_t *tman) { +void X_MB_handle_connection(Display *display, + redraw_man_t *rdman, + mb_tman_t *tman) { int fd; mb_timeval_t now, tmo; struct timeval tv; @@ -74,6 +146,9 @@ int nfds; int r; + rdman_redraw_all(rdman); + XFlush(display); + fd = XConnectionNumber(display); nfds = fd + 1; while(1) { @@ -105,3 +180,112 @@ } } } + +#define ERR -1 +#define OK 0 + +static int X_init_connection(const char *display_name, + int w, int h, + Display **displayp, + Visual **visualp, + Window *winp) { + Display *display; + Window root, win; + Visual *visual; + int screen; + XSetWindowAttributes wattr; + int depth; + int x, y; + int r; + + display = XOpenDisplay(display_name); + if(display == NULL) + return ERR; + + screen = DefaultScreen(display); + root = DefaultRootWindow(display); + visual = DefaultVisual(display, screen); + depth = DefaultDepth(display, screen); + 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; + } + + XSelectInput(display, win, PointerMotionMask | ExposureMask); + XFlush(display); + + *displayp = display; + *visualp = visual; + *winp = win; + + return OK; +} + +/*! \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. + */ +int X_MB_init(const char *display_name, + int w, int h, X_MB_runtime_t *xmb_rt) { + memset(xmb_rt, 0, sizeof(X_MB_runtime_t)); + + xmb_rt->w = w; + xmb_rt->h = h; + X_init_connection(display_name, w, h, &xmb_rt->display, + &xmb_rt->visual, &xmb_rt->win); + + xmb_rt->surface = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + + xmb_rt->backend_surface = + cairo_xlib_surface_create(xmb_rt->display, + xmb_rt->win, + xmb_rt->visual, + w, h); + + xmb_rt->cr = cairo_create(xmb_rt->surface); + xmb_rt->backend_cr = cairo_create(xmb_rt->backend_surface); + + cairo_set_source_surface(xmb_rt->backend_cr, xmb_rt->surface, 0, 0); + + xmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t)); + redraw_man_init(xmb_rt->rdman, xmb_rt->cr, xmb_rt->backend_cr); + + xmb_rt->tman = mb_tman_new(); + + return OK; +} + +void X_MB_destroy(X_MB_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->cr) + cairo_destroy(xmb_rt->cr); + if(xmb_rt->backend_cr) + cairo_destroy(xmb_rt->backend_cr); + + if(xmb_rt->surface) + cairo_surface_destroy(xmb_rt->surface); + if(xmb_rt->backend_surface) + cairo_surface_destroy(xmb_rt->backend_surface); + + if(xmb_rt->display) + XCloseDisplay(xmb_rt->display); +} +