Mercurial > MadButterfly
changeset 122:17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Mon, 15 Sep 2008 20:33:06 +0800 |
parents | 76ba6fd61c7d |
children | 9e2316dc6ecb |
files | examples/calculator/main.c examples/svg2code_ex/main.c examples/tank/tank_main.c src/X_supp.c src/X_supp.h src/animate.c src/observer.h |
diffstat | 7 files changed, 222 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/calculator/main.c Sun Sep 14 23:40:57 2008 +0800 +++ b/examples/calculator/main.c Mon Sep 15 20:33:06 2008 +0800 @@ -61,22 +61,26 @@ static void show_text(calc_data_t *calc_data, int num, int saved, int op, const char *suffix) { char buf[20]; + redraw_man_t *rdman; + + rdman = X_MB_rdman(calc_data->rt); sprintf(buf, "%d%s", num, suffix); sh_text_set_text(calc_data->code->screen_text, buf); - rdman_shape_changed(calc_data->rt->rdman, calc_data->code->screen_text); + rdman_shape_changed(rdman, calc_data->code->screen_text); if(op == 'n') sprintf(buf, "None"); else sprintf(buf, "%d%c", saved, op); sh_text_set_text(calc_data->code->saved_text, buf); - rdman_shape_changed(calc_data->rt->rdman, calc_data->code->saved_text); + rdman_shape_changed(rdman, calc_data->code->saved_text); } static void compute(calc_data_t *calc_data, coord_t *tgt) { int i; coord_t **coord_p; + redraw_man_t *rdman; static int valid_num = 0; static int factor = 1; static int num = 0; @@ -131,7 +135,8 @@ break; } } - rdman_redraw_changed(calc_data->rt->rdman); + rdman = X_MB_rdman(calc_data->rt); + rdman_redraw_changed(rdman); } static void buttons_handler(event_t *evt, void *arg) { @@ -149,11 +154,13 @@ ob_factory_t *factory; subject_t *subject; coord_t *coord; + redraw_man_t *rdman; int off; int i; calculator_scr = calc_data->code; - factory = rdman_get_ob_factory(calc_data->rt->rdman); + rdman = X_MB_rdman(calc_data->rt); + factory = rdman_get_ob_factory(rdman); for(i = 0; i < 16; i++) { off = tgt_list[i].off; @@ -164,23 +171,24 @@ } int main(int argc, char * const argv[]) { - X_MB_runtime_t rt; + X_MB_runtime_t *rt; + redraw_man_t *rdman; calculator_scr_t *calculator_scr; calc_data_t calc_data; - int r; - r = X_MB_init(":0.0", 300, 400, &rt); + rt = X_MB_new(":0.0", 300, 400); - calculator_scr = calculator_scr_new(rt.rdman); + rdman = X_MB_rdman(rt); + calculator_scr = calculator_scr_new(rdman); - calc_data.rt = &rt; + calc_data.rt = rt; calc_data.code = calculator_scr; setup_observers(&calc_data); - X_MB_handle_connection(&rt); + X_MB_handle_connection(rt); calculator_scr_free(calculator_scr); - X_MB_destroy(&rt); + X_MB_free(rt); return 0; }
--- a/examples/svg2code_ex/main.c Sun Sep 14 23:40:57 2008 +0800 +++ b/examples/svg2code_ex/main.c Mon Sep 15 20:33:06 2008 +0800 @@ -21,54 +21,57 @@ case EVT_MOUSE_BUT_PRESS: coord_show(ex_rt->code->file_menu); /* Tell redraw manager that a coord (group) is chagned. */ - rdman_coord_changed(ex_rt->rt->rdman, ex_rt->code->file_menu); + rdman_coord_changed(X_MB_rdman(ex_rt->rt), ex_rt->code->file_menu); /* Update changed part to UI. */ - rdman_redraw_changed(ex_rt->rt->rdman); + rdman_redraw_changed(X_MB_rdman(ex_rt->rt)); break; } } static void file_menu_handler(event_t *evt, void *arg) { ex_rt_t *ex_rt = (ex_rt_t *)arg; + redraw_man_t *rdman; + rdman = X_MB_rdman(ex_rt->rt); switch(evt->type) { case EVT_MOUSE_BUT_PRESS: coord_hide(ex_rt->code->file_menu); /* Tell redraw manager that a coord (group) is chagned. */ - rdman_coord_changed(ex_rt->rt->rdman, ex_rt->code->file_menu); + rdman_coord_changed(rdman, ex_rt->code->file_menu); /* Update changed part to UI. */ - rdman_redraw_changed(ex_rt->rt->rdman); + rdman_redraw_changed(rdman); break; } } int main(int argc, char * const argv[]) { - X_MB_runtime_t rt; + X_MB_runtime_t *rt; + redraw_man_t *rdman; svg2code_ex_t *svg2code; ob_factory_t *factory; subject_t *subject; ex_rt_t ex_rt; - int r; /* * Initialize a runtime with XLib as backend. */ - r = X_MB_init(":0.0", 800, 600, &rt); + rt = X_MB_new(":0.0", 800, 600); /* * Instantiate objects from a SVG file. */ - svg2code = svg2code_ex_new(rt.rdman); + rdman = X_MB_rdman(rt); + svg2code = svg2code_ex_new(rdman); /* * Get observer factory */ - factory = rdman_get_ob_factory(rt.rdman); + factory = rdman_get_ob_factory(rdman); /* * Register observers to subjects of events for objects. */ subject = coord_get_mouse_event(svg2code->file_button); - ex_rt.rt = &rt; + ex_rt.rt = rt; ex_rt.code = svg2code; subject_add_observer(factory, subject, file_button_handler, &ex_rt); subject = coord_get_mouse_event(svg2code->file_menu); @@ -78,13 +81,13 @@ * Start handle connections, includes one to X server. * User start to interact with the application. */ - X_MB_handle_connection(&rt); + X_MB_handle_connection(rt); /* * Clean */ svg2code_ex_free(svg2code); - X_MB_destroy(&rt); + X_MB_free(rt); return 0; }
--- a/examples/tank/tank_main.c Sun Sep 14 23:40:57 2008 +0800 +++ b/examples/tank/tank_main.c Mon Sep 15 20:33:06 2008 +0800 @@ -54,6 +54,7 @@ void initial_tank(tank_rt_t *tank_rt, X_MB_runtime_t *mb_rt) { redraw_man_t *rdman; + mb_tman_t *tman; mud_t *mud; brick_t *brick; rock_t *rock; @@ -63,7 +64,7 @@ mb_timeval_t mbtv; int i, j; - rdman = mb_rt->rdman; + rdman = X_MB_rdman(mb_rt); tank_rt->mb_rt = mb_rt; for(i = 0; i < 12; i++) { @@ -119,20 +120,21 @@ mb_shift_new(0, 150, tank_rt->tank1->root_coord, word); mb_shift_new(0, 150, tank_rt->tank2->root_coord, word); + tman = X_MB_tman(mb_rt); get_now(&mbtv); - mb_progm_start(tank_rt->tank1_progm, mb_rt->tman, &mbtv); + mb_progm_start(tank_rt->tank1_progm, tman, &mbtv); } int main(int argc, char *const argv[]) { - X_MB_runtime_t rt; + X_MB_runtime_t *rt; tank_rt_t tank_rt; - X_MB_init(":0.0", 800, 600, &rt); + rt = X_MB_new(":0.0", 800, 600); - initial_tank(&tank_rt, &rt); + initial_tank(&tank_rt, rt); - X_MB_handle_connection(&rt); + X_MB_handle_connection(rt); - X_MB_destroy(&rt); + X_MB_free(rt); }
--- a/src/X_supp.c Sun Sep 14 23:40:57 2008 +0800 +++ b/src/X_supp.c Mon Sep 15 20:33:06 2008 +0800 @@ -9,6 +9,108 @@ #include "mb_timer.h" #include "X_supp.h" +#define ERR -1 +#define OK 0 + +/*! \ingroup xkb + * @{ + */ +struct _X_kb_info { + int keycode_min, keycode_max; + int ksym_per_code; + KeySym *syms; + subject_t *kbevents; + ob_factory_t *ob_factory; +}; + +/* @} */ + +struct _X_MB_runtime { + Display *display; + Window win; + Visual *visual; + cairo_surface_t *surface, *backend_surface; + cairo_t *cr, *backend_cr; + redraw_man_t *rdman; + mb_tman_t *tman; + int w, h; + + X_kb_info_t kbinfo; + + /* States */ + shape_t *last; +}; + +/*! \defgroup xkb X Keyboard Handling + * + * Accept keyboard events from X server and delivery it to + * application through observer pattern. There is a subject, + * per X-connection, for that. + * @{ + */ +static int keycode2sym(X_kb_info_t *kbinfo, unsigned int keycode) { + int sym_idx; + int sym; + + sym_idx = kbinfo->ksym_per_code * (keycode - kbinfo->keycode_min); + sym = kbinfo->syms[sym_idx]; + return sym; +} + +static int X_kb_init(X_kb_info_t *kbinfo, Display *display, + redraw_man_t *rdman) { + int n_syms; + ob_factory_t *factory; + int r; + + r = XDisplayKeycodes(display, + &kbinfo->keycode_min, + &kbinfo->keycode_max); + if(r == 0) + return ERR; + + n_syms = kbinfo->keycode_max - kbinfo->keycode_min + 1; + kbinfo->syms = XGetKeyboardMapping(display, kbinfo->keycode_min, + n_syms, + &kbinfo->ksym_per_code); + if(kbinfo->syms == NULL) + return ERR; + + factory = rdman_get_ob_factory(rdman); + kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB); + if(kbinfo->kbevents == NULL) + return ERR; + kbinfo->ob_factory = factory; + + return OK; +} + +static void X_kb_destroy(X_kb_info_t *kbinfo) { + subject_free(kbinfo->ob_factory, kbinfo->kbevents); + XFree(kbinfo->syms); +} + +/*! \brief Accept X keyboard events from handle_x_event() and dispatch it. + */ +static void X_kb_handle_event(X_kb_info_t *kbinfo, XKeyEvent *xkey) { + unsigned int code; + int sym; + X_kb_event_t event; + + code = xkey->keycode; + sym = keycode2sym(kbinfo, code); + if(xkey->type == KeyPress) + event.event.type = EVT_KB_PRESS; + else if(xkey->type == KeyRelease) + event.event.type = EVT_KB_RELEASE; + event.event.tgt = event.event.cur_tgt = kbinfo->kbevents; + event.keycode = code; + event.sym = sym; + + subject_notify(kbinfo->ob_factory, kbinfo->kbevents, &event.event); +} + +/* @} */ static unsigned int get_button_state(unsigned int state) { unsigned int but = 0; @@ -72,6 +174,7 @@ XMotionEvent *mevt; XButtonEvent *bevt; XExposeEvent *eevt; + XKeyEvent *xkey; co_aix x, y, w, h; int eflag = 0; @@ -145,6 +248,12 @@ } break; + case KeyPress: + case KeyRelease: + xkey = &evt.xkey; + X_kb_handle_event(&rt->kbinfo, xkey); + break; + case Expose: eevt = &evt.xexpose; x = eevt->x; @@ -273,7 +382,8 @@ } XSelectInput(display, win, PointerMotionMask | ExposureMask | - ButtonPressMask | ButtonReleaseMask); + ButtonPressMask | ButtonReleaseMask | + KeyPressMask | KeyReleaseMask); XFlush(display); *displayp = display; @@ -288,7 +398,7 @@ * 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, +static 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)); @@ -318,10 +428,12 @@ xmb_rt->last = NULL; + X_kb_init(&xmb_rt->kbinfo, xmb_rt->display, xmb_rt->rdman); + return OK; } -void X_MB_destroy(X_MB_runtime_t *xmb_rt) { +static void X_MB_destroy(X_MB_runtime_t *xmb_rt) { if(xmb_rt->rdman) { redraw_man_destroy(xmb_rt->rdman); free(xmb_rt->rdman); @@ -342,5 +454,38 @@ if(xmb_rt->display) XCloseDisplay(xmb_rt->display); + + X_kb_destroy(&xmb_rt->kbinfo); } +X_MB_runtime_t *X_MB_new(const char *display_name, int w, int h) { + X_MB_runtime_t *rt; + int r; + + rt = O_ALLOC(X_MB_runtime_t); + if(rt == NULL) + return NULL; + + r = X_MB_init(display_name, w, h, rt); + if(r != OK) + return NULL; + + return rt; +} + +void X_MB_free(X_MB_runtime_t *rt) { + X_MB_destroy(rt); + free(rt); +} + +subject_t *X_MB_kbevents(X_MB_runtime_t *xmb_rt) { + return xmb_rt->kbinfo.kbevents; +} + +redraw_man_t *X_MB_rdman(X_MB_runtime_t *xmb_rt) { + return xmb_rt->rdman; +} + +mb_tman_t *X_MB_tman(X_MB_runtime_t *xmb_rt) { + return xmb_rt->tman; +}
--- a/src/X_supp.h Sun Sep 14 23:40:57 2008 +0800 +++ b/src/X_supp.h Mon Sep 15 20:33:06 2008 +0800 @@ -6,25 +6,28 @@ #include "mb_timer.h" #include "redraw_man.h" +/*! \ingroup xkb + * @{ + */ +typedef struct _X_kb_info X_kb_info_t; + +struct _X_kb_event { + event_t event; + int keycode; + int sym; +}; +typedef struct _X_kb_event X_kb_event_t; + +/* @} */ + typedef struct _X_MB_runtime X_MB_runtime_t; -struct _X_MB_runtime { - Display *display; - Window win; - Visual *visual; - cairo_surface_t *surface, *backend_surface; - cairo_t *cr, *backend_cr; - redraw_man_t *rdman; - mb_tman_t *tman; - int w, h; - - /* States */ - shape_t *last; -}; extern void X_MB_handle_connection(X_MB_runtime_t *rt); -extern int X_MB_init(const char *display_name, - int w, int h, X_MB_runtime_t *xmb_rt); -extern void X_MB_destroy(X_MB_runtime_t *xmb_rt); +extern X_MB_runtime_t *X_MB_new(const char *display_name, int w, int h); +extern void X_MB_free(X_MB_runtime_t *xmb_rt); +extern subject_t *X_MB_kbevents(X_MB_runtime_t *xmb_rt); +extern redraw_man_t *X_MB_rdman(X_MB_runtime_t *xmb_rt); +extern mb_tman_t *X_MB_tman(X_MB_runtime_t *xmb_rt); #endif
--- a/src/animate.c Sun Sep 14 23:40:57 2008 +0800 +++ b/src/animate.c Mon Sep 15 20:33:06 2008 +0800 @@ -74,7 +74,7 @@ #include "animate.h" -#define STEP_INTERVAL 50000 +#define STEP_INTERVAL 90000 #define ASSERT(x) /*! \brief A word is a set of concurrent actions in a program. @@ -201,9 +201,15 @@ } } -/* +/*! \brief Time stepping for a program. + * * Any two actions in concurrent words never change the same attribute. * Start time of words in a program are specified in incremental order. + * + * \note Program will take a big step at last monent. It is because + * mb_progm_step() running mb_word_stop() if the word being stop + * between now and next_tmo. It is not obviously if time stepping + * small. */ static void mb_progm_step(const mb_timeval_t *tmo, const mb_timeval_t *now,
--- a/src/observer.h Sun Sep 14 23:40:57 2008 +0800 +++ b/src/observer.h Mon Sep 15 20:33:06 2008 +0800 @@ -11,7 +11,7 @@ typedef void (*evt_handler)(event_t *event, void *arg); struct _event { - int type; + int type; /*!< event type (a.k.a. EVT_* */ subject_t *tgt, *cur_tgt; }; @@ -40,7 +40,7 @@ /*! \brief Flag that make a subject to propagate events to parents. */ #define SUBF_STOP_PROPAGATE 0x1 -enum {OBJT_GEO, OBJT_COORD}; +enum {OBJT_GEO, OBJT_COORD, OBJT_KB}; struct _mouse_event { event_t event; @@ -69,7 +69,8 @@ }; enum {EVT_MOUSE_OVER, EVT_MOUSE_OUT, EVT_MOUSE_MOVE, - EVT_MOUSE_BUT_PRESS, EVT_MOUSE_BUT_RELEASE}; + EVT_MOUSE_BUT_PRESS, EVT_MOUSE_BUT_RELEASE, + EVT_KB_PRESS, EVT_KB_RELEASE}; extern subject_t *subject_new(ob_factory_t *factory, void *obj, int obj_type);