# HG changeset patch # User sylee@eeepc # Date 1225383293 -28800 # Node ID f3366433eee55247aaef4948e6723b77a3a361de # Parent 7ca25f18902f1f0cb9db7cbb7e508c56343c13fb# Parent f3eccc24bdb2210fefe3054f9b91125e85238a34 Merge from MadButterfly official repository. diff -r 7ca25f18902f -r f3366433eee5 dox/first_program.h --- a/dox/first_program.h Fri Oct 31 00:12:17 2008 +0800 +++ b/dox/first_program.h Fri Oct 31 00:14:53 2008 +0800 @@ -16,9 +16,9 @@ * programs. * * For example, to translate foo.svg with steps - * - $(PREFIX)/bin/svg2code.py foo.svg foo.mb - * - m4 -I $(PREFIX)/share/mb mb_c_source.m4 foo.mb > foo.c - * - m4 -I $(PREFIX)/share/mb mb_c_header.m4 foo.mb > foo.h + * - \$(PREFIX)/bin/svg2code.py foo.svg foo.mb + * - m4 -I \$(PREFIX)/share/mb mb_c_source.m4 foo.mb > foo.c + * - m4 -I \$(PREFIX)/share/mb mb_c_header.m4 foo.mb > foo.h * * foo.h declares a structure, named 'foo' and two functions, * foo_new() and foo_free(). An instance of 'foo' holds all objects for diff -r 7ca25f18902f -r f3366433eee5 examples/calculator/Makefile --- a/examples/calculator/Makefile Fri Oct 31 00:12:17 2008 +0800 +++ b/examples/calculator/Makefile Fri Oct 31 00:14:53 2008 +0800 @@ -1,10 +1,13 @@ SVG=calculator_scr.svg TOOLSDIR=/usr/local/share/mb INCS=-I/usr/local/include -CFLAGS+=`pkg-config --cflags cairo` $(INCS) -Wall -LDFLAGS=-L/usr/local/lib `pkg-config --libs cairo` +CFLAGS+=`pkg-config --cflags cairo` $(INCS) -Wall -I../../src +LDFLAGS=-L/usr/local/lib `pkg-config --libs cairo` -L../../src LIBS=-lmbfly BINS= calc +SVG2CODE= ../../tools/svg2code.py +MB_C_HEADER= ../../tools/mb_c_header.m4 +MB_C_SOURCE= ../../tools/mb_c_source.m4 all: $(BINS) @@ -18,13 +21,13 @@ $(CC) -c $(CFLAGS) -o $@ $(SVG:C/.svg/.c/) $(SVG:C/.svg/.mb/): $(SVG) - /usr/local/bin/svg2code.py $(.ALLSRC) $@ + $(SVG2CODE) $(.ALLSRC) $@ $(SVG:C/.svg/.c/): $(SVG:C/.svg/.mb/) - m4 -I $(TOOLSDIR) mb_c_source.m4 $(.ALLSRC) > $@ + m4 -I $(TOOLSDIR) $(MB_C_SOURCE) $(.ALLSRC) > $@ $(SVG:C/.svg/.h/): $(SVG:C/.svg/.mb/) - m4 -I $(TOOLSDIR) mb_c_header.m4 $(.ALLSRC) > $@ + m4 -I $(TOOLSDIR) $(MB_C_HEADER) $(.ALLSRC) > $@ clean: for i in *.mb *.o *.core *~ $(SVG:C/.svg/.c/) $(SVG:C/.svg/.h/) $(BINS); do \ diff -r 7ca25f18902f -r f3366433eee5 examples/svg2code_ex/Makefile --- a/examples/svg2code_ex/Makefile Fri Oct 31 00:12:17 2008 +0800 +++ b/examples/svg2code_ex/Makefile Fri Oct 31 00:14:53 2008 +0800 @@ -1,10 +1,13 @@ SVG=svg2code_ex.svg TOOLSDIR=/usr/local/share/mb -INCS=-I/usr/local/include +INCS=-I/usr/local/include -I../../src/mb CFLAGS+=`pkg-config --cflags cairo` $(INCS) -Wall LDFLAGS=-L/usr/local/lib `pkg-config --libs cairo` LIBS=-lmbfly BINS= ex1 +SVG2CODE= ../../tools/svg2code.py +MB_C_HEADER= ../../tools/mb_c_header.m4 +MB_C_SOURCE= ../../tools/mb_c_source.m4 all: $(BINS) @@ -18,13 +21,13 @@ $(CC) -c $(CFLAGS) -o $@ $(SVG:C/.svg/.c/) $(SVG:C/.svg/.mb/): $(SVG) - /usr/local/bin/svg2code.py $(.ALLSRC) $@ + $(SVG2CODE) $(.ALLSRC) $@ $(SVG:C/.svg/.c/): $(SVG:C/.svg/.mb/) - m4 -I $(TOOLSDIR) mb_c_source.m4 $(.ALLSRC) > $@ + m4 -I $(TOOLSDIR) $(MB_C_SOURCE) $(.ALLSRC) > $@ $(SVG:C/.svg/.h/): $(SVG:C/.svg/.mb/) - m4 -I $(TOOLSDIR) mb_c_header.m4 $(.ALLSRC) > $@ + m4 -I $(TOOLSDIR) $(MB_C_HEADER) $(.ALLSRC) > $@ clean: for i in *.mb *.o *.core *~ $(SVG:C/.svg/.c/) $(SVG:C/.svg/.h/) $(BINS); do \ @@ -32,4 +35,4 @@ echo "delete $$i"; \ rm -f "$$i"; \ fi; \ - done \ No newline at end of file + done diff -r 7ca25f18902f -r f3366433eee5 examples/tank/Makefile --- a/examples/tank/Makefile Fri Oct 31 00:12:17 2008 +0800 +++ b/examples/tank/Makefile Fri Oct 31 00:14:53 2008 +0800 @@ -1,15 +1,20 @@ SVGS = brick.svg bullet.svg bush.svg mud.svg rock.svg \ - tank1.svg tank2.svg tank_en.svg + tank1.svg tank2.svg tank_en.svg bang.svg SVGHS = $(SVGS:C/\.svg/.h/) SVGCS = $(SVGS:C/\.svg/.c/) SVGOS = $(SVGS:C/\.svg/.o/) MBS = $(SVGS:C/\.svg/.mb/) SVG2CODE= svg2code.py +MB_C_HEADER= mb_c_header.m4 +MB_C_SOURCE= mb_c_source.m4 M4 = m4 -M4FLAGS = -I /usr/local/share/mb +M4MACRODIR?= /usr/local/share/mb +M4FLAGS ?= -I $(M4MACRODIR) LDFLAGS += -LIBS += -lmbfly -lX11 -L/usr/local/lib `pkg-config --libs cairo` -CFLAGS += -I/usr/local/include `pkg-config --cflags cairo` +INCDIR?= /usr/local/include +LIBDIR?= /usr/local/lib +LIBS += -lmbfly -lX11 -L$(LIBDIR) `pkg-config --libs cairo` -L../../src +CFLAGS += -I$(INCDIR) `pkg-config --cflags cairo` -I../../src BIN = tank all: tank @@ -38,10 +43,10 @@ $(SVG2CODE) $(SVG) $@ $(SVG:C/\.svg/.h/): $(SVG:C/\.svg/.mb/) - $(M4) $(M4FLAGS) mb_c_header.m4 $(.ALLSRC) > $@ + $(M4) $(M4FLAGS) $(MB_C_HEADER) $(.ALLSRC) > $@ $(SVG:C/\.svg/.c/): $(SVG:C/\.svg/.mb/) - $(M4) $(M4FLAGS) mb_c_source.m4 $(.ALLSRC) > $@ + $(M4) $(M4FLAGS) $(MB_C_SOURCE) $(.ALLSRC) > $@ .endfor diff -r 7ca25f18902f -r f3366433eee5 examples/tank/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/tank/README Fri Oct 31 00:14:53 2008 +0800 @@ -0,0 +1,5 @@ + Turn to left. + Turn to right. + Turn to up. + Turn to down. + To Fire. diff -r 7ca25f18902f -r f3366433eee5 examples/tank/bang.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/tank/bang.svg Fri Oct 31 00:14:53 2008 +0800 @@ -0,0 +1,92 @@ + + + + + + + + + + + image/svg+xml + + + + + + + Bang + + diff -r 7ca25f18902f -r f3366433eee5 examples/tank/tank_main.c --- a/examples/tank/tank_main.c Fri Oct 31 00:12:17 2008 +0800 +++ b/examples/tank/tank_main.c Fri Oct 31 00:14:53 2008 +0800 @@ -1,3 +1,4 @@ +#include #include #include #include @@ -40,17 +41,34 @@ * \brief Tank elf module provides control functions of tanks in game. * @{ */ +struct _tank_bullet { + redraw_man_t *rdman; + coord_t *coord_pos; + coord_t *coord_rot; + bullet_t *bullet_obj; + int start_map_x, start_map_y; + int direction; + mb_progm_t *progm; + mb_timeval_t start_time; + observer_t *ob_redraw; + mb_timer_t *hit_tmr; + mb_tman_t *tman; +}; +typedef struct _tank_bullet tank_bullet_t; +enum { BU_UP = 0, BU_RIGHT, BU_DOWN, BU_LEFT }; + struct _tank { coord_t *coord_pos; /*!< \brief coordinate for position */ coord_t *coord_rot; /*!< \brief coordinate for rotation */ + coord_t *coord_center; int map_x, map_y; int direction; mb_progm_t *progm; + tank_bullet_t *bullet; }; typedef struct _tank tank_t; enum { TD_UP = 0, TD_RIGHT, TD_DOWN, TD_LEFT }; - /* @} */ typedef struct _tank_rt tank_rt_t; @@ -92,6 +110,7 @@ tank->map_y = map_y; tank->direction = TD_UP; tank->progm = NULL; + tank->bullet = NULL; memset(coord_pos->matrix, 0, sizeof(co_aix[6])); coord_pos->matrix[0] = 1; @@ -108,7 +127,7 @@ if(tank->progm) { tman = X_MB_tman(xmb_rt); - mb_progm_abort(tank->progm, tman); + mb_progm_abort(tank->progm); } free(tank); } @@ -233,6 +252,217 @@ /* @} */ +/*! \brief Make coord objects for bullet elfs. */ +static void make_bullet_elf_coords(redraw_man_t *rdman, coord_t **coord_pos, + coord_t **coord_rot, + coord_t **coord_center) { + coord_t *coord_back; + + *coord_pos = rdman_coord_new(rdman, rdman->root_coord); + + coord_back = rdman_coord_new(rdman, *coord_pos); + coord_back->matrix[2] = 25; + coord_back->matrix[5] = 25; + rdman_coord_changed(rdman, coord_back); + + *coord_rot = rdman_coord_new(rdman, coord_back); + + *coord_center = rdman_coord_new(rdman, *coord_rot); + (*coord_center)->matrix[2] = -5; + (*coord_center)->matrix[5] = +15; + rdman_coord_changed(rdman, *coord_center); +} + +static tank_bullet_t *tank_bullet_new(redraw_man_t *rdman, + int map_x, int map_y, + int direction) { + tank_bullet_t *bullet; + coord_t *coord_center; + co_aix *matrix; + static float _sins[] = { 0, 1, 0, -1}; + static float _coss[] = { 1, 0, -1, 0}; + float _sin, _cos; + + bullet = O_ALLOC(tank_bullet_t); + bullet->rdman = rdman; + + make_bullet_elf_coords(rdman, &bullet->coord_pos, + &bullet->coord_rot, + &coord_center); + bullet->bullet_obj = bullet_new(rdman, coord_center); + + bullet->start_map_x = map_x; + bullet->start_map_y = map_y; + bullet->direction = direction; + bullet->progm = NULL; + + matrix = bullet->coord_pos->matrix; + matrix[2] = map_x * 50; + matrix[5] = map_y * 50; + rdman_coord_changed(rdman, bullet->coord_pos); + + _sin = _sins[direction]; + _cos = _coss[direction]; + matrix = bullet->coord_rot->matrix; + matrix[0] = _cos; + matrix[1] = -_sin; + matrix[3] = _sin; + matrix[4] = _cos; + + return bullet; +} + +static void tank_bullet_free(tank_bullet_t *bullet) { + bullet_free(bullet->bullet_obj); + rdman_coord_subtree_free(bullet->rdman, bullet->coord_pos); +} + +static void bullet_go_out_map_and_redraw(event_t *event, void *arg) { + tank_t *tank = (tank_t *)arg; + tank_bullet_t *bullet; + + bullet = tank->bullet; + mb_progm_free(bullet->progm); + tank_bullet_free(tank->bullet); + tank->bullet = NULL; +} + +static void bullet_go_out_map(event_t *event, void *arg) { + tank_t *tank = (tank_t *)arg; + tank_bullet_t *bullet; + redraw_man_t *rdman; + + bullet = tank->bullet; + rdman = bullet->rdman; + + if(bullet->hit_tmr != NULL) + mb_tman_remove(bullet->tman, bullet->hit_tmr); + + coord_hide(bullet->coord_pos); + rdman_coord_changed(rdman, bullet->coord_pos); + + /*! \todo Simplify the procdure of using observer pattern. */ + + bullet_go_out_map_and_redraw(NULL, tank); +} + +static void bullet_bang(tank_bullet_t *bullet, int map_x, int map_y) { +} + +static void bullet_hit_chk(const mb_timeval_t *tmo, + const mb_timeval_t *now, + void *arg) { + tank_t *tank = (tank_t *)arg; + tank_bullet_t *bullet; + mb_timeval_t diff, next; + mb_timeval_t unit_tm; + float move_units_f; + int move_units; + int x, y; + int dir; + static int move_adj[][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}}; + + bullet = tank->bullet; + MB_TIMEVAL_CP(&diff, now); + MB_TIMEVAL_DIFF(&diff, &bullet->start_time); + MB_TIMEVAL_SET(&unit_tm, 0, 250000); + move_units_f = MB_TIMEVAL_DIV(&diff, &unit_tm); + move_units = floorl(move_units_f); + dir = bullet->direction; + x = bullet->start_map_x + move_adj[dir][0] * move_units; + y = bullet->start_map_y + move_adj[dir][1] * move_units; + + if(map[y][x] != MUD) { + bullet->hit_tmr = NULL; + mb_progm_abort(bullet->progm); + bullet_go_out_map(NULL, arg); + bullet_bang(bullet, x, y); + } else { + MB_TIMEVAL_SET(&next, 0, 100000); + MB_TIMEVAL_ADD(&next, now); + bullet->hit_tmr = mb_tman_timeout(bullet->tman, &next, + bullet_hit_chk, arg); + } +} + +static void tank_fire_bullet(tank_rt_t *tank_rt, tank_t *tank) { + X_MB_runtime_t *xmb_rt; + redraw_man_t *rdman; + int map_x, map_y; + int shift_x, shift_y; + int shift_len; + int dir; + tank_bullet_t *bullet; + mb_progm_t *progm; + mb_word_t *word; + mb_action_t *act; + mb_timeval_t start, playing; + mb_timeval_t now, next; + ob_factory_t *factory; + mb_tman_t *tman; + subject_t *subject; + static int map_xy_adj[][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}}; + + if(tank->bullet != NULL) + return; + + xmb_rt = tank_rt->mb_rt; + rdman = X_MB_rdman(xmb_rt); + tman = X_MB_tman(xmb_rt); + + dir = tank->direction; + map_x = tank->map_x + map_xy_adj[dir][0]; + map_y = tank->map_y + map_xy_adj[dir][1]; + switch(dir) { + case TD_UP: + shift_len = map_y + 1; + shift_x = 0; + shift_y = -shift_len * 50; + break; + case TD_RIGHT: + shift_len = 16 - map_x; + shift_x = shift_len * 50; + shift_y = 0; + break; + case TD_DOWN: + shift_len = 12 - map_y; + shift_x = 0; + shift_y = shift_len * 50; + break; + case TD_LEFT: + shift_len = map_x + 1; + shift_x = -shift_len * 50; + shift_y = 0; + break; + } + + if(shift_len <= 0) + return; + + tank->bullet = tank_bullet_new(rdman, map_x, map_y, dir); + bullet = tank->bullet; + bullet->tman = tman; + + progm = mb_progm_new(2, rdman); + MB_TIMEVAL_SET(&start, 0, 0); + MB_TIMEVAL_SET(&playing, shift_len / 4, (shift_len % 4) * 250000); + word = mb_progm_next_word(progm, &start, &playing); + act = mb_shift_new(shift_x, shift_y, bullet->coord_pos, word); + bullet->progm = progm; + + subject = mb_progm_get_complete(progm); + factory = rdman_get_ob_factory(rdman); + subject_add_observer(factory, subject, bullet_go_out_map, tank); + + get_now(&now); + MB_TIMEVAL_CP(&bullet->start_time, &now); + mb_progm_start(progm, tman, &now); + + MB_TIMEVAL_SET(&next, 0, 100000); + MB_TIMEVAL_ADD(&next, &now); + bullet->hit_tmr = mb_tman_timeout(tman, &next, bullet_hit_chk, tank); +} + #define CHANGE_POS(g, x, y) do { \ (g)->root_coord->matrix[0] = 1.0; \ (g)->root_coord->matrix[2] = x; \ @@ -252,27 +482,32 @@ switch(xkey->sym) { case 0xff51: /* left */ direction = TD_LEFT; + tank_move(tank_rt->tank1, direction, tank_rt); break; case 0xff52: /* up */ direction = TD_UP; + tank_move(tank_rt->tank1, direction, tank_rt); break; case 0xff53: /* right */ direction = TD_RIGHT; + tank_move(tank_rt->tank1, direction, tank_rt); break; case 0xff54: /* down */ direction = TD_DOWN; + tank_move(tank_rt->tank1, direction, tank_rt); break; case 0x20: /* space */ + tank_fire_bullet(tank_rt, tank_rt->tank1); + break; case 0xff0d: /* enter */ default: return; } - tank_move(tank_rt->tank1, direction, tank_rt); } static void init_keyboard(tank_rt_t *tank_rt) { diff -r 7ca25f18902f -r f3366433eee5 src/X_main.c --- a/src/X_main.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/X_main.c Fri Oct 31 00:14:53 2008 +0800 @@ -148,15 +148,15 @@ coord2 = rdman_coord_new(&rdman, rdman.root_coord); coord3 = rdman_coord_new(&rdman, rdman.root_coord); - fill1 = paint_color_new(&rdman, 1, 1, 0, 0.5); - fill2 = paint_color_new(&rdman, 0, 1, 1, 0.5); - stroke = paint_color_new(&rdman, 0.4, 0.4, 0.4, 1); - text_stroke = paint_color_new(&rdman, 0.5, 0.5, 0.5, 1); + fill1 = rdman_paint_color_new(&rdman, 1, 1, 0, 0.5); + fill2 = rdman_paint_color_new(&rdman, 0, 1, 1, 0.5); + stroke = rdman_paint_color_new(&rdman, 0.4, 0.4, 0.4, 1); + text_stroke = rdman_paint_color_new(&rdman, 0.5, 0.5, 0.5, 1); face = cairo_get_font_face(tmpcr); - text = sh_text_new("hello \xe6\xbc\xa2\xe5\xad\x97", 10, h / 4, - 36.0, face); - text_fill = paint_radial_new(&rdman, 100, h / 4, 70); + text = rdman_shape_text_new(&rdman, "hello \xe6\xbc\xa2\xe5\xad\x97", + 10, h / 4, 36.0, face); + text_fill = rdman_paint_radial_new(&rdman, 100, h / 4, 70); grad_stop_init(text_stops, 0, 0.2, 0.9, 0.2, 1); grad_stop_init(text_stops + 1, 1, 0.9, 0.2, 0.2, 0.1); paint_radial_stops(text_fill, 2, text_stops); @@ -165,7 +165,7 @@ rdman_paint_fill(&rdman, text_fill, text); rdman_add_shape(&rdman, text, coord3); - path1 = sh_path_new("M 22,89.36218 C -34,-0.63782 39,-9.637817 82,12.36218 C 125,34.36218 142,136.36218 142,136.36218 C 100.66667,125.36218 74.26756,123.42795 22,89.36218 z "); + path1 = rdman_shape_path_new(&rdman, "M 22,89.36218 C -34,-0.63782 39,-9.637817 82,12.36218 C 125,34.36218 142,136.36218 142,136.36218 C 100.66667,125.36218 74.26756,123.42795 22,89.36218 z "); rdman_paint_fill(&rdman, fill1, path1); rdman_paint_stroke(&rdman, stroke, path1); coord1->matrix[0] = 0.8; @@ -174,7 +174,7 @@ coord1->matrix[4] = 0.8; coord1->matrix[5] = 20; - path2 = sh_path_new("M 22,89.36218 C -34,-0.63782 39,-9.637817 82,12.36218 C 125,34.36218 142,136.36218 142,136.36218 C 100.66667,125.36218 74.26756,123.42795 22,89.36218 z "); + path2 = rdman_shape_path_new(&rdman, "M 22,89.36218 C -34,-0.63782 39,-9.637817 82,12.36218 C 125,34.36218 142,136.36218 142,136.36218 C 100.66667,125.36218 74.26756,123.42795 22,89.36218 z "); rdman_paint_fill(&rdman, fill2, path2); rdman_paint_stroke(&rdman, stroke, path2); coord2->matrix[0] = -0.8; @@ -189,12 +189,12 @@ rdman_add_shape(&rdman, (shape_t *)path2, coord2); - fill3 = paint_linear_new(&rdman, 50, 50, 150, 150); + fill3 = rdman_paint_linear_new(&rdman, 50, 50, 150, 150); grad_stop_init(fill3_stops, 0, 1, 0, 0, 0.5); grad_stop_init(fill3_stops + 1, 0.5, 0, 1, 0, 0.5); grad_stop_init(fill3_stops + 2, 1, 0, 0, 1, 0.5); paint_linear_stops(fill3, 3, fill3_stops); - rect = sh_rect_new(50, 50, 100, 100, 20, 20); + rect = rdman_shape_rect_new(&rdman, 50, 50, 100, 100, 20, 20); rdman_paint_fill(&rdman, fill3, rect); rdman_add_shape(&rdman, (shape_t *)rect, rdman.root_coord); @@ -243,16 +243,16 @@ mb_tman_free(tman); } - fill1->free(fill1); - fill2->free(fill2); - stroke->free(stroke); - text_stroke->free(text_stroke); - text_fill->free(text_fill); + rdman_paint_free(&rdman, fill1); + rdman_paint_free(&rdman, fill2); + rdman_paint_free(&rdman, stroke); + rdman_paint_free(&rdman, text_stroke); + rdman_paint_free(&rdman, text_fill); + rdman_shape_free(&rdman, path1); + rdman_shape_free(&rdman, path2); + rdman_shape_free(&rdman, rect); + rdman_shape_free(&rdman, text); redraw_man_destroy(&rdman); - path1->free(path1); - path2->free(path2); - rect->free(rect); - text->free(text); cairo_destroy(tmpcr); cairo_surface_destroy(tmpsuf); } diff -r 7ca25f18902f -r f3366433eee5 src/animate.c --- a/src/animate.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/animate.c Fri Oct 31 00:14:53 2008 +0800 @@ -98,6 +98,7 @@ int first_playing; /*!< first playing word. */ mb_tman_t *tman; subject_t *complete; /*!< notify when a program is completed. */ + mb_timer_t *cur_timer; int n_words; int max_words; @@ -289,7 +290,9 @@ MB_TIMEVAL_CP(&next_tmo, &word->abs_start); timer = mb_tman_timeout(progm->tman, &next_tmo, mb_progm_step, progm); + progm->cur_timer = timer; } else { + /* Make program to complete. */ #ifndef UNITTEST factory = rdman_get_ob_factory(progm->rdman); comp_evt.event.type = EVT_PROGM_COMPLETE; @@ -297,6 +300,7 @@ comp_evt.progm = progm; subject_notify(factory, progm->complete, &comp_evt.event); #endif /* UNITTEST */ + progm->cur_timer = NULL; } } @@ -329,10 +333,17 @@ timer = mb_tman_timeout(tman, &progm->words[0].abs_start, mb_progm_step, progm); ASSERT(timer != NULL); + + /* We need timer to abort it. */ + progm->cur_timer = timer; } -void mb_progm_abort(mb_progm_t *progm, mb_tman_t *tman) { +void mb_progm_abort(mb_progm_t *progm) { /*! \todo Make sure abort release resources. */ + if(progm->cur_timer) { + mb_tman_remove(progm->tman, progm->cur_timer); + progm->cur_timer = NULL; + } } /*! \brief Return event subject for completion of a program. diff -r 7ca25f18902f -r f3366433eee5 src/animate.h --- a/src/animate.h Fri Oct 31 00:12:17 2008 +0800 +++ b/src/animate.h Fri Oct 31 00:14:53 2008 +0800 @@ -42,7 +42,7 @@ const mb_timeval_t *playing); extern void mb_progm_start(mb_progm_t *progm, mb_tman_t *tman, mb_timeval_t *now); -extern void mb_progm_abort(mb_progm_t *progm, mb_tman_t *tman); +extern void mb_progm_abort(mb_progm_t *progm); extern subject_t *mb_progm_get_complete(mb_progm_t *progm); /*! \defgroup ani_actions Animation Actions diff -r 7ca25f18902f -r f3366433eee5 src/coord.c --- a/src/coord.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/coord.c Fri Oct 31 00:14:53 2008 +0800 @@ -120,22 +120,33 @@ return sqrt(x * x + y * y); } +/*! + * \note Coords, marked with COF_SKIP_TRIVAL (for temporary), and + * descendants of them will not be trivaled and the flag with be removed + * after skipping them. + */ coord_t *preorder_coord_subtree(coord_t *root, coord_t *last) { - coord_t *next; + coord_t *next = NULL; ASSERT(last != NULL); - if(STAILQ_HEAD(last->children)) + if((!(last->flags & COF_SKIP_TRIVAL)) && + STAILQ_HEAD(last->children)) { next = STAILQ_HEAD(last->children); - else { + if(!(next->flags & COF_SKIP_TRIVAL)) + return next; + } else { next = last; + } + + do { + next->flags &= ~COF_SKIP_TRIVAL; while(next != root && STAILQ_NEXT(coord_t, sibling, next) == NULL) next = next->parent; if(next == root) - next = NULL; - if(next) - next = STAILQ_NEXT(coord_t, sibling, next); - } + return NULL; + next = STAILQ_NEXT(coord_t, sibling, next); + } while(next->flags & COF_SKIP_TRIVAL); return next; } diff -r 7ca25f18902f -r f3366433eee5 src/event.c --- a/src/event.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/event.c Fri Oct 31 00:14:53 2008 +0800 @@ -11,17 +11,7 @@ #define ARRAY_EXT_SZ 64 -static int extend_memblk(void **buf, int o_size, int n_size) { - void *new_buf; - - new_buf = realloc(*buf, n_size); - if(new_buf == NULL) - return ERR; - - *buf = new_buf; - - return OK; -} +DARRAY_DEFINE(geos, geo_t *); /*! \brief Add a geo_t object to general geo list. * @@ -31,21 +21,10 @@ * from a redraw manager. */ static int add_gen_geo(redraw_man_t *rdman, geo_t *geo) { - int max_gen_geos; int r; - if(rdman->n_gen_geos >= rdman->max_gen_geos) { - max_gen_geos = rdman->max_gen_geos + ARRAY_EXT_SZ; - r = extend_memblk((void **)&rdman->gen_geos, - sizeof(geo_t *) * rdman->n_gen_geos, - sizeof(geo_t *) * max_gen_geos); - if(r != OK) - return ERR; - rdman->max_gen_geos = max_gen_geos; - } - - rdman->gen_geos[rdman->n_gen_geos++] = geo; - return OK; + r = geos_add(&rdman->gen_geos, geo); + return r == 0? OK: ERR; } static int collect_shapes_at_point(redraw_man_t *rdman, @@ -57,7 +36,7 @@ if(r != OK) return ERR; - rdman->n_gen_geos = 0; + rdman->gen_geos.num = 0; for(geo = rdman_geos(rdman, NULL); geo != NULL; @@ -94,9 +73,9 @@ cairo_t *cr; int i; - geos = rdman->gen_geos; + geos = rdman->gen_geos.ds; cr = rdman->cr; - for(i = rdman->n_gen_geos - 1; i >= 0; i--) { + for(i = rdman->gen_geos.num - 1; i >= 0; i--) { geo = geos[i]; if(geo->flags & GEF_HIDDEN) continue; diff -r 7ca25f18902f -r f3366433eee5 src/mb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mb Fri Oct 31 00:14:53 2008 +0800 @@ -0,0 +1,1 @@ +. \ No newline at end of file diff -r 7ca25f18902f -r f3366433eee5 src/mb_timer.h --- a/src/mb_timer.h Fri Oct 31 00:12:17 2008 +0800 +++ b/src/mb_timer.h Fri Oct 31 00:14:53 2008 +0800 @@ -67,6 +67,9 @@ (a)->tv_usec -= 1000000; \ } \ } while(0) +#define MB_TIMEVAL_DIV(a, b) \ + (((a)->tv_sec * 1000000.0 + (a)->tv_usec) / \ + ((b)->tv_sec * 1000000.0 + (b)->tv_usec)) extern void get_now(mb_timeval_t *tmo); diff -r 7ca25f18902f -r f3366433eee5 src/mb_types.h --- a/src/mb_types.h Fri Oct 31 00:12:17 2008 +0800 +++ b/src/mb_types.h Fri Oct 31 00:14:53 2008 +0800 @@ -12,20 +12,26 @@ typedef struct _shnode shnode_t; typedef struct _paint paint_t; +struct _redraw_man; + /*! \brief Base of paint types. * - * Paints should be freed by users by calling paint_t::free() of + * Paints should be freed by users by calling rdman_paint_free() of * the paint. * * \todo move member functions to a seperate structure and setup a * singleton fro each paint type. */ struct _paint { + int flags; void (*prepare)(paint_t *paint, cairo_t *cr); - void (*free)(paint_t *paint); + void (*free)(struct _redraw_man *rdman, paint_t *paint); STAILQ(shnode_t) members; + paint_t *pnt_next; /*!< \brief Collect all paints of a rdman. */ }; +#define PNTF_FREE 0x1 + struct _shnode { shape_t *shape; shnode_t *next; @@ -52,7 +58,8 @@ subject_t *mouse_event; }; #define GEF_DIRTY 0x1 -#define GEF_HIDDEN 0x2 +#define GEF_HIDDEN 0x2 /*!< The geo is hidden. */ +#define GEF_FREE 0x4 extern int is_overlay(area_t *r1, area_t *r2); extern void area_init(area_t *area, int n_pos, co_aix pos[][2]); @@ -109,14 +116,21 @@ * of parent. */ int num_members; - STAILQ(geo_t) members; /*!< All geo_t members in this coord. */ + STAILQ(geo_t) members; /*!< \brief All geo_t members in this coord. */ + + STAILQ(shape_t) shapes; /*!< \brief All shapes managed by the rdman. */ + subject_t *mouse_event; } coord_t; #define COF_DIRTY 0x1 -#define COF_HIDDEN 0x2 +#define COF_HIDDEN 0x2 /*!< A coord is hidden. */ #define COF_OWN_CANVAS 0x4 /*!< A coord owns a canvas or inherit it - * from an ancestor. + * from an ancestor. */ +#define COF_SKIP_TRIVAL 0x8 /*!< temporary skip descendants + * when trivaling. + */ +#define COF_FREE 0x10 extern void coord_init(coord_t *co, coord_t *parent); extern void coord_trans_pos(coord_t *co, co_aix *x, co_aix *y); @@ -125,7 +139,13 @@ extern void update_aggr_matrix(coord_t *start); extern coord_t *preorder_coord_subtree(coord_t *root, coord_t *last); extern coord_t *postorder_coord_subtree(coord_t *root, coord_t *last); -#define coord_hide(co) do { co->flags |= COF_HIDDEN; } while(0) +extern void preorder_coord_skip_subtree(coord_t *subroot); +#define preorder_coord_skip_subtree(sub) \ + do { (sub)->flags |= COF_SKIP_TRIVAL; } while(0) +#define coord_hide(co) \ + do { \ + (co)->flags |= COF_HIDDEN; \ + } while(0) #define coord_show(co) do { co->flags &= ~COF_HIDDEN; } while(0) #define coord_get_mouse_event(coord) ((coord)->mouse_event) @@ -150,26 +170,20 @@ co_aix stroke_width; int stroke_linecap:2; int stroke_linejoin:2; + struct _shape *sh_next; /*!< Link all shapes of a rdman together. */ void (*free)(shape_t *shape); }; enum { SHT_UNKNOW, SHT_PATH, SHT_TEXT, SHT_RECT }; -#define sh_attach_geo(sh, g) \ - do { \ - (sh)->geo = g; \ - (g)->shape = (shape_t *)(sh); \ +#define sh_get_mouse_event_subject(sh) ((sh)->geo->mouse_event) +#define sh_hide(sh) \ + do { \ + (sh)->geo->flags |= GEF_HIDDEN; \ } while(0) -#define sh_detach_geo(sh) \ - do { \ - (sh)->geo->shape = NULL; \ - (sh)->geo = NULL; \ +#define sh_show(sh) \ + do { \ + (sh)->geo->flags &= ~GEF_HIDDEN; \ } while(0) -#define sh_get_geo(sh) ((sh)->geo) -#define sh_get_mouse_event_subject(sh) ((sh)->geo->mouse_event) -#define sh_hide(sh) do { (sh)->geo->flags |= GEF_HIDDEN; } while(0) -#define sh_show(sh) do { (sh)->geo->flags &= ~GEF_HIDDEN; } while(0) -#define sh_attach_coord(sh, coord) do { (sh)->coord = coord; } while(0) -#define sh_detach_coord(sh) do { (sh)->coord = NULL; } while(0) #endif /* __MB_TYPES_H_ */ diff -r 7ca25f18902f -r f3366433eee5 src/observer.h --- a/src/observer.h Fri Oct 31 00:12:17 2008 +0800 +++ b/src/observer.h Fri Oct 31 00:14:53 2008 +0800 @@ -42,7 +42,7 @@ #define SUBF_BUSY 0x2 /*!< \brief in subject_notify() */ #define SUBF_FREE 0x4 /*!< \brief in postponding subject_free() */ -enum {OBJT_GEO, OBJT_COORD, OBJT_KB, OBJT_PROGM}; +enum {OBJT_GEO, OBJT_COORD, OBJT_KB, OBJT_PROGM, OBJT_RDMAN}; struct _mouse_event { event_t event; @@ -72,7 +72,8 @@ enum {EVT_MOUSE_OVER, EVT_MOUSE_OUT, EVT_MOUSE_MOVE, EVT_MOUSE_BUT_PRESS, EVT_MOUSE_BUT_RELEASE, - EVT_KB_PRESS, EVT_KB_RELEASE, EVT_PROGM_COMPLETE}; + EVT_KB_PRESS, EVT_KB_RELEASE, EVT_PROGM_COMPLETE, + EVT_RDMAN_REDRAW }; extern subject_t *subject_new(ob_factory_t *factory, void *obj, int obj_type); diff -r 7ca25f18902f -r f3366433eee5 src/paint.c --- a/src/paint.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/paint.c Fri Oct 31 00:14:53 2008 +0800 @@ -10,7 +10,6 @@ typedef struct _paint_color { paint_t paint; co_comp_t r, g, b, a; - redraw_man_t *rdman; } paint_color_t; int _paint_color_size = sizeof(paint_color_t); @@ -22,22 +21,19 @@ cairo_set_source_rgba(cr, color->r, color->g, color->b, color->a); } -static void paint_color_free(paint_t *paint) { - paint_color_t *color = (paint_color_t *)paint; - - shnode_list_free(color->rdman, paint->members); - free(paint); +static void paint_color_free(redraw_man_t *rdman, paint_t *paint) { + shnode_list_free(rdman, paint->members); + elmpool_elm_free(rdman->paint_color_pool, paint); } -paint_t *paint_color_new(redraw_man_t *rdman, - co_comp_t r, co_comp_t g, - co_comp_t b, co_comp_t a) { +paint_t *rdman_paint_color_new(redraw_man_t *rdman, + co_comp_t r, co_comp_t g, + co_comp_t b, co_comp_t a) { paint_color_t *color; color = (paint_color_t *)elmpool_elm_alloc(rdman->paint_color_pool); if(color == NULL) return NULL; - color->rdman = rdman; color->r = r; color->g = g; color->b = b; @@ -107,7 +103,7 @@ cairo_set_source(cr, ptn); } -static void paint_linear_free(paint_t *paint) { +static void paint_linear_free(redraw_man_t *rdman, paint_t *paint) { paint_linear_t *linear = (paint_linear_t *)paint; if(linear->ptn) @@ -115,8 +111,9 @@ free(paint); } -paint_t *paint_linear_new(redraw_man_t *rdman, - co_aix x1, co_aix y1, co_aix x2, co_aix y2) { +paint_t *rdman_paint_linear_new(redraw_man_t *rdman, + co_aix x1, co_aix y1, + co_aix x2, co_aix y2) { paint_linear_t *linear; linear = (paint_linear_t *)malloc(sizeof(paint_linear_t)); @@ -196,7 +193,7 @@ cairo_set_source(cr, radial->ptn); } -static void paint_radial_free(paint_t *paint) { +static void paint_radial_free(redraw_man_t *rdman, paint_t *paint) { paint_radial_t *radial = (paint_radial_t *)paint; if(radial->ptn) @@ -204,8 +201,8 @@ free(paint); } -paint_t *paint_radial_new(redraw_man_t *rdman, - co_aix cx, co_aix cy, co_aix r) { +paint_t *rdman_paint_radial_new(redraw_man_t *rdman, + co_aix cx, co_aix cy, co_aix r) { paint_radial_t *radial; radial = O_ALLOC(paint_radial_t); diff -r 7ca25f18902f -r f3366433eee5 src/paint.h --- a/src/paint.h Fri Oct 31 00:12:17 2008 +0800 +++ b/src/paint.h Fri Oct 31 00:14:53 2008 +0800 @@ -8,9 +8,9 @@ typedef float co_comp_t; -extern paint_t *paint_color_new(redraw_man_t *rdman, - co_comp_t r, co_comp_t g, - co_comp_t b, co_comp_t a); +extern paint_t *rdman_paint_color_new(redraw_man_t *rdman, + co_comp_t r, co_comp_t g, + co_comp_t b, co_comp_t a); extern void paint_color_set(paint_t *paint, co_comp_t r, co_comp_t g, co_comp_t b, co_comp_t a); @@ -19,9 +19,11 @@ co_comp_t *b, co_comp_t *a); #define paint_init(_paint, _prepare, _free) \ do { \ + (_paint)->flags = 0; \ (_paint)->prepare = _prepare; \ (_paint)->free = _free; \ STAILQ_INIT((_paint)->members); \ + (_paint)->pnt_next = NULL; \ } while(0) \ @@ -30,13 +32,14 @@ co_comp_t r, g, b, a; } grad_stop_t; -extern paint_t *paint_linear_new(redraw_man_t *rdman, - co_aix x1, co_aix y1, co_aix x2, co_aix y2); +extern paint_t *rdman_paint_linear_new(redraw_man_t *rdman, + co_aix x1, co_aix y1, + co_aix x2, co_aix y2); extern grad_stop_t *paint_linear_stops(paint_t *paint, int n_stops, grad_stop_t *stops); -extern paint_t *paint_radial_new(redraw_man_t *rdman, - co_aix cx, co_aix cy, co_aix r); +extern paint_t *rdman_paint_radial_new(redraw_man_t *rdman, + co_aix cx, co_aix cy, co_aix r); extern grad_stop_t *paint_radial_stops(paint_t *paint, int n_stops, grad_stop_t *stops); diff -r 7ca25f18902f -r f3366433eee5 src/redraw_man.c --- a/src/redraw_man.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/redraw_man.c Fri Oct 31 00:14:53 2008 +0800 @@ -12,6 +12,24 @@ /* NOTE: bounding box should also consider width of stroke. */ +#define sh_attach_geo(sh, g) \ + do { \ + (sh)->geo = g; \ + (g)->shape = (shape_t *)(sh); \ + } while(0) +#define sh_detach_geo(sh) \ + do { \ + (sh)->geo->shape = NULL; \ + (sh)->geo = NULL; \ + } while(0) +#define sh_get_geo(sh) ((sh)->geo) +#define sh_attach_coord(sh, coord) do { (sh)->coord = coord; } while(0) +#define sh_detach_coord(sh) do { (sh)->coord = NULL; } while(0) +#define rdman_is_dirty(rdman) \ + ((rdman)->dirty_coords.num != 0 || \ + (rdman)->dirty_geos.num != 0 || \ + (rdman)->dirty_areas.num != 0) + #define OK 0 #define ERR -1 @@ -56,6 +74,16 @@ STAILQ_REMOVE((coord)->members, geo_t, coord_next, (member)) #define FIRST_MEMBER(coord) STAILQ_HEAD((coord)->members) +/* Functions for paint members. */ +#define FORPAINTMEMBERS(paint, member) \ + for((member) = STAILQ_HEAD((paint)->members); \ + (member) != NULL; \ + (member) = STAILQ_NEXT(paint_t, next, member)) +#define RM_PAINTMEMBER(paint, member) \ + STAILQ_REMOVE((paint)->members, shnode_t, next, member) +#define RM_PAINT(rdman, paint) \ + STAILQ_REMOVE((rdman)->paints, paint_t, pnt_next, paint) + /*! \brief Sort a list of element by a unsigned integer. * * The result is in ascend order. The unsigned integers is @@ -78,55 +106,68 @@ } } -static int extend_memblk(void **buf, int o_size, int n_size) { - void *new_buf; +DARRAY_DEFINE(coords, coord_t *); +DARRAY_DEFINE(geos, geo_t *); +DARRAY_DEFINE(areas, area_t *); + +/*! Use \brief DARRAY to implement dirty & free lists. + */ +#define ADD_DATA(sttype, field, v) \ + int r; \ + r = sttype ## _add(&rdman->field, v); \ + return r == 0? OK: ERR; + + +static int add_dirty_coord(redraw_man_t *rdman, coord_t *coord) { + coord->flags |= COF_DIRTY; + ADD_DATA(coords, dirty_coords, coord); +} + +static int add_dirty_geo(redraw_man_t *rdman, geo_t *geo) { + geo->flags |= GEF_DIRTY; + ADD_DATA(geos, dirty_geos, geo); +} - new_buf = realloc(*buf, n_size); - if(new_buf == NULL) - return ERR; +static int add_dirty_area(redraw_man_t *rdman, area_t *area) { + ADD_DATA(areas, dirty_areas, area); +} + +static int add_free_obj(redraw_man_t *rdman, void *obj, + free_func_t free_func) { + int max; + free_obj_t *new_objs, *free_obj; - *buf = new_buf; + if(rdman->free_objs.num >= rdman->free_objs.max) { + max = rdman->free_objs.num + ARRAY_EXT_SZ; + new_objs = realloc(rdman->free_objs.objs, + max * sizeof(free_obj_t)); + if(new_objs == NULL) + return ERR; + rdman->free_objs.max = max; + rdman->free_objs.objs = new_objs; + } + + free_obj = rdman->free_objs.objs + rdman->free_objs.num++; + free_obj->obj = obj; + free_obj->free_func = free_func; return OK; } -static int add_dirty_geo(redraw_man_t *rdman, geo_t *geo) { - int max_dirty_geos; - int r; +static void free_free_objs(redraw_man_t *rdman) { + int i; + free_obj_t *free_obj; - if(rdman->n_dirty_geos >= rdman->max_dirty_geos) { - max_dirty_geos = rdman->max_dirty_geos + ARRAY_EXT_SZ; - r = extend_memblk((void **)&rdman->dirty_geos, - sizeof(geo_t *) * rdman->n_dirty_geos, - sizeof(geo_t *) * max_dirty_geos); - if(r != OK) - return ERR; - rdman->max_dirty_geos = max_dirty_geos; + for(i = 0; i < rdman->free_objs.num; i++) { + free_obj = &rdman->free_objs.objs[i]; + free_obj->free_func(rdman, free_obj->obj); } - - rdman->dirty_geos[rdman->n_dirty_geos++] = geo; - return OK; + rdman->free_objs.num = 0; } -static int add_dirty_area(redraw_man_t *rdman, area_t *area) { - int max_dirty_areas; - int r; - - if(rdman->n_dirty_areas >= rdman->max_dirty_areas) { - /* every geo object and coord object can contribute 2 areas. - * rdman_draw_area() may also contribute 1 area. - */ - max_dirty_areas = rdman->max_dirty_areas + ARRAY_EXT_SZ; - r = extend_memblk((void **)&rdman->dirty_areas, - sizeof(area_t *) * rdman->n_dirty_areas, - sizeof(area_t *) * max_dirty_areas); - if(r != OK) - return ERR; - rdman->max_dirty_areas = max_dirty_areas; - } - - rdman->dirty_areas[rdman->n_dirty_areas++] = area; - return OK; +static void free_objs_destroy(redraw_man_t *rdman) { + if(rdman->free_objs.objs != NULL) + free(rdman->free_objs.objs); } static void area_to_positions(area_t *area, co_aix (*poses)[2]) { @@ -250,6 +291,9 @@ rdman->ob_factory.observer_free = ob_observer_free; rdman->ob_factory.get_parent_subject = ob_get_parent_subject; + rdman->redraw = + subject_new(&rdman->ob_factory, rdman, OBJT_RDMAN); + rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); if(rdman->root_coord == NULL) redraw_man_destroy(rdman); @@ -265,18 +309,46 @@ rdman->cr = cr; rdman->backend = backend; + STAILQ_INIT(rdman->shapes); + STAILQ_INIT(rdman->paints); + return OK; } void redraw_man_destroy(redraw_man_t *rdman) { coord_t *coord, *saved_coord; + shape_t *shape, *saved_shape; + geo_t *member; + + free_free_objs(rdman); + free_objs_destroy(rdman); coord = postorder_coord_subtree(rdman->root_coord, NULL); while(coord) { saved_coord = coord; coord = postorder_coord_subtree(rdman->root_coord, coord); + FORMEMBERS(saved_coord, member) { + rdman_shape_free(rdman, member->shape); + } rdman_coord_free(rdman, saved_coord); } + FORMEMBERS(saved_coord, member) { + rdman_shape_free(rdman, member->shape); + } + /* Resources of root_coord is free by elmpool_free() or + * caller; for canvas + */ + + shape = saved_shape = STAILQ_HEAD(rdman->shapes); + while(shape && (shape = STAILQ_NEXT(shape_t, sh_next, shape))) { + rdman_shape_free(rdman, saved_shape); +#if 0 + STAILQ_REMOVE(rdman->shapes, shape_t, sh_next, saved_shape); +#endif + saved_shape = shape; + } + if(saved_shape != NULL) + rdman_shape_free(rdman, saved_shape); elmpool_free(rdman->coord_pool); elmpool_free(rdman->geo_pool); @@ -284,12 +356,11 @@ elmpool_free(rdman->observer_pool); elmpool_free(rdman->subject_pool); elmpool_free(rdman->paint_color_pool); - if(rdman->dirty_coords) - free(rdman->dirty_coords); - if(rdman->dirty_geos) - free(rdman->dirty_geos); - if(rdman->gen_geos) - free(rdman->gen_geos); + + DARRAY_DESTROY(&rdman->dirty_coords); + DARRAY_DESTROY(&rdman->dirty_geos); + DARRAY_DESTROY(&rdman->dirty_areas); + DARRAY_DESTROY(&rdman->gen_geos); } @@ -330,7 +401,6 @@ geo_attach_coord(geo, coord); /* New one should be dirty to recompute it when drawing. */ - geo->flags |= GEF_DIRTY; r = add_dirty_geo(rdman, geo); if(r != OK) return ERR; @@ -343,22 +413,101 @@ /*! \brief Remove a shape object from redraw manager. * + * \note Shapes should be removed after redrawing or when rdman is in clean. + * \note Removing shapes or coords when a rdman is dirty, removing + * is postponsed. * \todo redraw shape objects that overlaid with removed one. */ -int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { +int rdman_shape_free(redraw_man_t *rdman, shape_t *shape) { geo_t *geo; - coord_t *coord; + int r; geo = shape->geo; - coord = shape->coord; - geo_detach_coord(geo, coord); - subject_free(&rdman->ob_factory, geo->mouse_event); - sh_detach_geo(shape); - elmpool_elm_free(rdman->geo_pool, shape->geo); - sh_detach_coord(shape); + + if(rdman_is_dirty(rdman) && geo != NULL) { + if(geo->flags & GEF_FREE) + return ERR; + + geo->flags |= GEF_FREE; + sh_hide(shape); + if(!(geo->flags & GEF_DIRTY)) { + r = add_dirty_geo(rdman, geo); + if(r != OK) + return ERR; + } + r = add_free_obj(rdman, shape, (free_func_t)rdman_shape_free); + if(r != OK) + return ERR; + return OK; + } + + if(geo != NULL) { + geo_detach_coord(geo, shape->coord); + sh_detach_coord(shape); + sh_detach_geo(shape); + subject_free(&rdman->ob_factory, geo->mouse_event); + elmpool_elm_free(rdman->geo_pool, geo); + } + STAILQ_REMOVE(rdman->shapes, shape_t, sh_next, shape); + shape->free(shape); return OK; } +shnode_t *shnode_new(redraw_man_t *rdman, shape_t *shape) { + shnode_t *node; + + node = (shnode_t *)elmpool_elm_alloc(rdman->shnode_pool); + if(node) { + node->shape = shape; + node->next = NULL; + } + return node; +} + +int rdman_paint_free(redraw_man_t *rdman, paint_t *paint) { + shnode_t *shnode, *saved_shnode; + + if(rdman_is_dirty(rdman)) { + if(!(paint->flags & PNTF_FREE)) + return ERR; + add_free_obj(rdman, paint, (free_func_t)rdman_paint_free); + paint->flags |= PNTF_FREE; + return OK; + } + + /* Free member shapes that using this paint. */ + saved_shnode = NULL; + FORPAINTMEMBERS(paint, shnode) { + if(saved_shnode) { + RM_PAINTMEMBER(paint, saved_shnode); + shnode_free(rdman, saved_shnode); + } + saved_shnode = shnode; + } + if(saved_shnode) { + RM_PAINTMEMBER(paint, saved_shnode); + shnode_free(rdman, saved_shnode); + } + + RM_PAINT(rdman, paint); + paint->free(rdman, paint); + return OK; +} + +void _rdman_paint_real_remove_child(redraw_man_t *rdman, + paint_t *paint, + shape_t *shape) { + shnode_t *shnode; + + FORPAINTMEMBERS(paint, shnode) { + if(shnode->shape == shape) { + RM_PAINTMEMBER(paint, shnode); + shnode_free(rdman, shnode); + break; + } + } +} + coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { coord_t *coord, *root_coord; coord_t *visit; @@ -391,6 +540,10 @@ coord->before_pmem = parent->num_members; + /* If parent is dirty, children should be dirty. */ + if(parent && (parent->flags & COF_DIRTY)) + add_dirty_coord(rdman, coord); + return coord; } @@ -398,14 +551,44 @@ * * \param coord is a coord_t without children and members. * \return 0 for successful, -1 for error. + * + * \note Removing coords when the rdman is dirty, the removing is postponsed. */ int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) { coord_t *parent; + coord_t *child; + geo_t *member; + int r; parent = coord->parent; if(parent == NULL) return ERR; + if(rdman_is_dirty(rdman)) { + if(coord->flags & COF_FREE) + return ERR; + + FORCHILDREN(coord, child) { + if(!(child->flags & COF_FREE)) + return ERR; + } + FORMEMBERS(coord, member) { + if(!(member->flags & GEF_FREE)) + return ERR; + } + coord->flags |= COF_FREE; + coord_hide(coord); + if(!(coord->flags & COF_DIRTY)) { + r = add_dirty_coord(rdman, coord); + if(r != OK) + return ERR; + } + r = add_free_obj(rdman, coord, (free_func_t)rdman_coord_free); + if(r != OK) + return ERR; + return OK; + } + if(FIRST_MEMBER(coord) != NULL) return ERR; @@ -424,42 +607,61 @@ return OK; } -static void make_sure_dirty_coords(redraw_man_t *rdman) { - int max_dirty_coords; +int rdman_coord_subtree_free(redraw_man_t *rdman, coord_t *subtree) { + coord_t *coord, *prev_coord; int r; - - if(rdman->n_dirty_coords >= rdman->max_dirty_coords) { - /* Max of dirty_coords is not big enough. */ - max_dirty_coords = rdman->max_dirty_coords + 16; - - r = extend_memblk((void **)&rdman->dirty_coords, - sizeof(coord_t *) * rdman->n_dirty_coords, - sizeof(coord_t *) * max_dirty_coords); - rdman->max_dirty_coords = max_dirty_coords; + + if(subtree == NULL) + return OK; + + prev_coord = postorder_coord_subtree(subtree, NULL); + for(coord = postorder_coord_subtree(subtree, prev_coord); + coord != NULL; + coord = postorder_coord_subtree(subtree, coord)) { + if(!(prev_coord->flags & COF_FREE)) { + r = rdman_coord_free(rdman, prev_coord); + if(r != OK) + return ERR; + } + prev_coord = coord; } + if(!(prev_coord->flags & COF_FREE)) { + r = rdman_coord_free(rdman, prev_coord); + if(r != OK) + return ERR; + } + + return OK; } /*! \brief Mark a coord is changed. * * A changed coord_t object is marked as dirty and put - * into dirty_coords list. + * into dirty_coords list. rdman_coord_changed() should be called + * for a coord after it been changed to notify redraw manager to + * redraw shapes grouped by it. */ int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) { coord_t *child; if(coord->flags & COF_DIRTY) return OK; - - /* Make the coord and child coords dirty. */ - for(child = coord; + + add_dirty_coord(rdman, coord); + + if(coord->flags & COF_HIDDEN) + return OK; + + /* Make child coords dirty. */ + for(child = preorder_coord_subtree(coord, coord); child != NULL; child = preorder_coord_subtree(coord, child)) { - if(child->flags & COF_DIRTY) + if(child->flags & (COF_DIRTY | COF_HIDDEN)) { + preorder_coord_skip_subtree(child); continue; - make_sure_dirty_coords(rdman); - - rdman->dirty_coords[rdman->n_dirty_coords++] = child; - child->flags |= COF_DIRTY; + } + + add_dirty_coord(rdman, child); } return OK; @@ -477,7 +679,6 @@ r = add_dirty_geo(rdman, geo); if(r == ERR) return ERR; - geo->flags |= GEF_DIRTY; return OK; } @@ -492,13 +693,11 @@ } int rdman_paint_changed(redraw_man_t *rdman, paint_t *paint) { - shnode_t *node; + shnode_t *shnode; int r; - for(node = STAILQ_HEAD(paint->members); - node != NULL; - node = STAILQ_NEXT(shnode_t, next, node)) { - r = _rdman_shape_changed(rdman, node->shape); + FORPAINTMEMBERS(paint, shnode) { + r = _rdman_shape_changed(rdman, shnode->shape); if(r != OK) return ERR; } @@ -536,9 +735,9 @@ shape->geo->flags &= ~GEF_DIRTY; if(is_coord_subtree_hidden(shape->coord)) - shape->geo->flags |= GEF_HIDDEN; + sh_hide(shape); else - shape->geo->flags &= ~GEF_HIDDEN; + sh_show(shape); } /*! \brief Setup canvas for the coord. @@ -615,9 +814,9 @@ int n_dirty_coords; int i, r; - n_dirty_coords = rdman->n_dirty_coords; + n_dirty_coords = rdman->dirty_coords.num; if(n_dirty_coords > 0) { - dirty_coords = rdman->dirty_coords; + dirty_coords = rdman->dirty_coords.ds; _insert_sort((void **)dirty_coords, n_dirty_coords, OFFSET(coord_t, order)); for(i = 0; i < n_dirty_coords; i++) { @@ -631,7 +830,7 @@ add_dirty_area(rdman, &coord->areas[0]); add_dirty_area(rdman, &coord->areas[1]); } - rdman->n_dirty_coords = 0; + rdman->dirty_coords.num = 0; } return OK; } @@ -642,9 +841,9 @@ geo_t **dirty_geos; geo_t *visit_geo; - n_dirty_geos = rdman->n_dirty_geos; + n_dirty_geos = rdman->dirty_geos.num; if(n_dirty_geos > 0) { - dirty_geos = rdman->dirty_geos; + dirty_geos = rdman->dirty_geos.ds; for(i = 0; i < n_dirty_geos; i++) { visit_geo = dirty_geos[i]; if(!(visit_geo->flags & GEF_DIRTY)) @@ -655,7 +854,7 @@ add_dirty_area(rdman, visit_geo->cur_area); add_dirty_area(rdman, visit_geo->last_area); } - rdman->n_dirty_geos = 0; + rdman->dirty_geos.num = 0; } return OK; @@ -837,6 +1036,9 @@ cairo_t *canvas; int mem_idx; + if(coord->flags & COF_HIDDEN) + return OK; + canvas = coord->canvas; member = FIRST_MEMBER(coord); mem_idx = 0; @@ -848,10 +1050,12 @@ child = NEXT_CHILD(child); } else { ASSERT(member != NULL); - if(is_geo_in_areas(member, n_areas, areas)) { + if((!(member->flags & GEF_HIDDEN)) && + is_geo_in_areas(member, n_areas, areas)) { draw_shape(rdman, canvas, member->shape); dirty = 1; } + member = NEXT_MEMBER(member); mem_idx++; } @@ -908,24 +1112,36 @@ int r; int n_dirty_areas; area_t **dirty_areas; + event_t event; + ob_factory_t *factory; + subject_t *redraw; r = clean_rdman_dirties(rdman); if(r != OK) return ERR; - n_dirty_areas = rdman->n_dirty_areas; - dirty_areas = rdman->dirty_areas; + n_dirty_areas = rdman->dirty_areas.num; + dirty_areas = rdman->dirty_areas.ds; if(n_dirty_areas > 0) { /*! \brief Draw shapes in preorder of coord tree and support opacity * rules. */ clean_canvas(rdman->cr); draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas); - copy_cr_2_backend(rdman, rdman->n_dirty_areas, rdman->dirty_areas); - rdman->n_dirty_areas = 0; + copy_cr_2_backend(rdman, rdman->dirty_areas.num, + rdman->dirty_areas.ds); reset_clip(rdman); } - rdman->n_dirty_areas = 0; + rdman->dirty_areas.num = 0; + + /* Free postponsed removing */ + free_free_objs(rdman); + + factory = rdman_get_ob_factory(rdman); + redraw = rdman_get_redraw_subject(rdman); + event.type = EVT_RDMAN_REDRAW; + event.tgt = event.cur_tgt = redraw; + subject_notify(factory, redraw, &event); return OK; } @@ -953,12 +1169,14 @@ * \sa * - rdman_redraw_all() * - rdman_redraw_changed() - * = draw_shapes_in_areas() + * - draw_shapes_in_areas() */ int rdman_redraw_all(redraw_man_t *rdman) { + area_t area; +#ifndef UNITTEST cairo_surface_t *surface; - area_t area; +#endif int r; area.x = area.y = 0; @@ -1027,17 +1245,6 @@ return r; } -shnode_t *shnode_new(redraw_man_t *rdman, shape_t *shape) { - shnode_t *node; - - node = (shnode_t *)elmpool_elm_alloc(rdman->shnode_pool); - if(node) { - node->shape = shape; - node->next = NULL; - } - return node; -} - /*! \page dirty Dirty geo, coord, and area. * * \section dirty_of_ego Dirty of geo @@ -1073,6 +1280,28 @@ * coords will also clean member geos. */ +/*! \page man_obj Manage Objects. + * + * Shapes and paints should also be managed by redraw manager. Redraw + * manager must know life-cycle of shapes and paints to avoid to use them + * after being free. If a shape is released when it is dirty, redraw + * manager will try to access them, after released, for redrawing. + * We can make a copy information need by redraw manager to redraw them, + * but it is more complicate, and induce runtime overhead. + * + * So, redraw manage had better also manage life-cycle of shapes and paints. + * Shapes and paints should be created and freed through interfaces + * provided by redraw manager. To reduce overhead of interfaces, they can + * be implemented as C macros. + * + * To refactory redraw manage to manage life-cycle of shapes and paints, + * following functions/macros are introduced. + * - rdman_paint_*_new() + * - rdman_paint_free() + * - rdman_shape_*_new() + * - rdman_shape_free() + */ + /* * When redraw an area, the affected elements may also extend to * outside of the area. Since the order of drawing will change @@ -1183,7 +1412,12 @@ int draw_cnt; }; -shape_t *sh_dummy_new(co_aix x, co_aix y, co_aix w, co_aix h) { +void sh_dummy_free(shape_t *sh) { + free(sh); +} + +shape_t *sh_dummy_new(redraw_man_t *rdman, + co_aix x, co_aix y, co_aix w, co_aix h) { sh_dummy_t *dummy; dummy = (sh_dummy_t *)malloc(sizeof(sh_dummy_t)); @@ -1198,14 +1432,13 @@ dummy->h = h; dummy->trans_cnt = 0; dummy->draw_cnt = 0; + dummy->shape.free = sh_dummy_free; + + rdman_shape_man(rdman, (shape_t *)dummy); return (shape_t *)dummy; } -void sh_dummy_free(shape_t *sh) { - free(sh); -} - void sh_dummy_transform(shape_t *shape) { sh_dummy_t *dummy = (sh_dummy_t *)shape; co_aix poses[2][2]; @@ -1240,7 +1473,7 @@ static void dummy_paint_prepare(paint_t *paint, cairo_t *cr) { } -static void dummy_paint_free(paint_t *paint) { +static void dummy_paint_free(redraw_man_t *rdman, paint_t *paint) { if(paint) free(paint); } @@ -1257,7 +1490,7 @@ return paint; } -void test_rdman_redraw_changed(void) { +static void test_rdman_redraw_changed(void) { coord_t *coords[3]; shape_t *shapes[3]; sh_dummy_t **dummys; @@ -1272,7 +1505,7 @@ redraw_man_init(rdman, NULL, NULL); paint = dummy_paint_new(rdman); for(i = 0; i < 3; i++) { - shapes[i] = sh_dummy_new(0, 0, 50, 50); + shapes[i] = sh_dummy_new(rdman, 0, 0, 50, 50); rdman_paint_fill(rdman, paint, shapes[i]); coords[i] = rdman_coord_new(rdman, rdman->root_coord); coords[i]->matrix[2] = 10 + i * 100; @@ -1298,15 +1531,39 @@ CU_ASSERT(dummys[1]->draw_cnt == 2); CU_ASSERT(dummys[2]->draw_cnt == 2); - paint->free(paint); + rdman_paint_free(rdman, paint); redraw_man_destroy(rdman); } +static int test_free_pass = 0; + +static void test_free(redraw_man_t *rdman, void *obj) { + test_free_pass++; +} + +static void test_rdman_free_objs(void) { + redraw_man_t *rdman; + redraw_man_t _rdman; + int i; + + redraw_man_init(&_rdman, NULL, NULL); + rdman = &_rdman; + + test_free_pass = 0; + + for(i = 0; i < 4; i++) + add_free_obj(rdman, NULL, test_free); + + redraw_man_destroy(rdman); + CU_ASSERT(test_free_pass == 4); +} + CU_pSuite get_redraw_man_suite(void) { CU_pSuite suite; suite = CU_add_suite("Suite_redraw_man", NULL, NULL); CU_ADD_TEST(suite, test_rdman_redraw_changed); + CU_ADD_TEST(suite, test_rdman_free_objs); return suite; } diff -r 7ca25f18902f -r f3366433eee5 src/redraw_man.h --- a/src/redraw_man.h Fri Oct 31 00:12:17 2008 +0800 +++ b/src/redraw_man.h Fri Oct 31 00:14:53 2008 +0800 @@ -6,6 +6,24 @@ #include "mb_types.h" #include "observer.h" +typedef struct _redraw_man redraw_man_t; + +typedef void (*free_func_t)(redraw_man_t *rdman, void *obj); +struct _free_obj { + void *obj; + free_func_t free_func; +}; +typedef struct _free_obj free_obj_t; +struct _free_objs { + int num, max; + free_obj_t *objs; +}; +typedef struct _free_objs free_objs_t; + +DARRAY(coords, coord_t *); +DARRAY(geos, geo_t *); +DARRAY(areas, area_t *); + /*! \brief Manage redrawing of shapes (graphic elements). * * Every coord_t and geo_t object is assigned with a unique @@ -21,7 +39,7 @@ * Dirty flag is clear when the transformation matrix of a coord * object been recomputed or when a geo_t objects been redrawed. */ -typedef struct _redraw_man { +struct _redraw_man { unsigned int next_coord_order; int n_coords; coord_t *root_coord; @@ -33,29 +51,24 @@ elmpool_t *subject_pool; elmpool_t *paint_color_pool; - int max_dirty_coords; - int n_dirty_coords; - coord_t **dirty_coords; /*!< coordinates their transform - * matric are chagned. - */ + coords_t dirty_coords; + geos_t dirty_geos; + areas_t dirty_areas; - int max_dirty_geos; - int n_dirty_geos; - geo_t **dirty_geos; /*!< geometries that need re-computed */ + geos_t gen_geos; - int max_dirty_areas; - int n_dirty_areas; - area_t **dirty_areas; /*!< \brief are areas need to redraw. */ + STAILQ(shape_t) shapes; /*!< \brief All managed shapes. */ + STAILQ(paint_t) paints; /*!< \brief All managed paints. */ - int max_gen_geos; - int n_gen_geos; - geo_t **gen_geos; /* general geo list (for temporary store) */ + free_objs_t free_objs; cairo_t *cr; cairo_t *backend; ob_factory_t ob_factory; -} redraw_man_t; + + subject_t *redraw; /*!< \brief Notified after redrawing. */ +}; extern int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, cairo_t *backend); @@ -65,9 +78,18 @@ geo_t ***overlays); extern int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord); -extern int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape); +/*! \brief Make a shape been managed by a redraw manager. */ +#define rdman_shape_man(rdman, shape) \ + STAILQ_INS_TAIL(rdman->shapes, shape_t, sh_next, shape) +extern int rdman_shape_free(redraw_man_t *rdman, shape_t *shape); + +#define rdman_paint_man(rdman, paint) \ + STAILQ_INS_TAIL(rdman->paints, paint_t, pnt_next, shape) +extern int rdman_paint_free(redraw_man_t *rdman, paint_t *paint); + extern coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent); extern int rdman_coord_free(redraw_man_t *rdman, coord_t *coord); +extern int rdman_coord_subtree_free(redraw_man_t *rdman, coord_t *subtree); extern int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord); extern int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape); extern int rdman_redraw_changed(redraw_man_t *rdman); @@ -101,21 +123,38 @@ shnode_t, next, __node); \ } \ } while(0) +extern void _rdman_paint_real_remove_child(redraw_man_t *rdman, + paint_t *paint, + shape_t *shape); +#define _rdman_paint_remove_child(rdman, paint, shape) \ + do { \ + if((shape)->fill == (shape)->stroke && \ + (shape)->stroke == paint) \ + break; \ + _rdman_paint_real_remove_child(rdman, paint, shape); \ + } while(0) #define rdman_paint_fill(rdman, paint, shape) \ do { \ + if((shape)->fill == paint) \ + break; \ + _rdman_paint_remove_child(rdman, paint, shape); \ _rdman_paint_child(rdman, paint, shape); \ - shape->fill = paint; \ + (shape)->fill = paint; \ } while(0) #define rdman_paint_stroke(rdman, paint, shape) \ do { \ + if((shape)->stroke == paint) \ + break; \ + _rdman_paint_remove_child(rdman, paint, shape); \ _rdman_paint_child(rdman, paint, shape); \ - shape->stroke = paint; \ + (shape)->stroke = paint; \ } while(0) extern int rdman_paint_changed(redraw_man_t *rdman, paint_t *paint); extern shape_t *find_shape_at_pos(redraw_man_t *rdman, co_aix x, co_aix y, int *in_stroke); #define rdman_get_ob_factory(rdman) (&(rdman)->ob_factory) +#define rdman_get_redraw_subject(rdman) ((rdman)->redraw) #endif /* __REDRAW_MAN_H_ */ diff -r 7ca25f18902f -r f3366433eee5 src/shape_path.c --- a/src/shape_path.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/shape_path.c Fri Oct 31 00:14:53 2008 +0800 @@ -4,6 +4,7 @@ #include #include #include "mb_types.h" +#include "redraw_man.h" /*! \brief Implement respective objects for SVG path tag. * @@ -660,7 +661,7 @@ /*! \brief Create a path from value of 'data' of SVG path. */ -shape_t *sh_path_new(char *data) { +shape_t *rdman_shape_path_new(redraw_man_t *rdman, char *data) { sh_path_t *path; int cmd_cnt, arg_cnt, fix_arg_cnt; int msz; @@ -705,6 +706,10 @@ path->shape.free = sh_path_free; +#ifndef UNITTEST + rdman_shape_man(rdman, (shape_t *)path); +#endif + return (shape_t *)path; } @@ -834,11 +839,11 @@ #include -void test_sh_path_new(void) { +void test_rdman_shape_path_new(void) { sh_path_t *path; co_aix *args; - path = (sh_path_t *)sh_path_new("M 33 25l33 55c 33 87 44 22 55 99L33 77z"); + path = (sh_path_t *)rdman_shape_path_new(NULL, "M 33 25l33 55c 33 87 44 22 55 99L33 77z"); CU_ASSERT(path != NULL); CU_ASSERT(path->cmd_len == ((5 + RESERVED_AIXS + 3) & ~0x3)); CU_ASSERT(path->arg_len == 12); @@ -867,7 +872,7 @@ coord_t coord; geo_t geo; - path = (sh_path_t *)sh_path_new("M 33 25l33 55C 33 87 44 22 55 99L33 77z"); + path = (sh_path_t *)rdman_shape_path_new(NULL, "M 33 25l33 55C 33 87 44 22 55 99L33 77z"); CU_ASSERT(path != NULL); CU_ASSERT(path->cmd_len == ((5 + RESERVED_AIXS + 3) & ~0x3)); CU_ASSERT(path->arg_len == 12); @@ -908,7 +913,8 @@ sh_path_t *path; path = (sh_path_t *) - sh_path_new(" M 33 25l33 55C 33 87 44 22 55 99L33 77z "); + rdman_shape_path_new(NULL, + " M 33 25l33 55C 33 87 44 22 55 99L33 77z "); CU_ASSERT(path != NULL); sh_path_free((shape_t *)path); } @@ -917,7 +923,7 @@ CU_pSuite suite; suite = CU_add_suite("Suite_shape_path", NULL, NULL); - CU_ADD_TEST(suite, test_sh_path_new); + CU_ADD_TEST(suite, test_rdman_shape_path_new); CU_ADD_TEST(suite, test_path_transform); return suite; diff -r 7ca25f18902f -r f3366433eee5 src/shape_rect.c --- a/src/shape_rect.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/shape_rect.c Fri Oct 31 00:14:53 2008 +0800 @@ -16,8 +16,9 @@ free(shape); } -shape_t *sh_rect_new(co_aix x, co_aix y, co_aix w, co_aix h, - co_aix rx, co_aix ry) { +shape_t *rdman_shape_rect_new(redraw_man_t *rdman, + co_aix x, co_aix y, co_aix w, co_aix h, + co_aix rx, co_aix ry) { sh_rect_t *rect; rect = (sh_rect_t *)malloc(sizeof(sh_rect_t)); @@ -35,6 +36,8 @@ rect->ry = ry; rect->shape.free = sh_rect_free; + rdman_shape_man(rdman, (shape_t *)rect); + return (shape_t *)rect; } diff -r 7ca25f18902f -r f3366433eee5 src/shape_text.c --- a/src/shape_text.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/shape_text.c Fri Oct 31 00:14:53 2008 +0800 @@ -32,8 +32,9 @@ cairo_font_face_destroy(text->face); } -shape_t *sh_text_new(const char *txt, co_aix x, co_aix y, - co_aix font_size, cairo_font_face_t *face) { +shape_t *rdman_shape_text_new(redraw_man_t *rdman, + const char *txt, co_aix x, co_aix y, + co_aix font_size, cairo_font_face_t *face) { sh_text_t *text; text = (sh_text_t *)malloc(sizeof(sh_text_t)); @@ -56,6 +57,8 @@ text->shape.free = sh_text_free; + rdman_shape_man(rdman, (shape_t *)text); + return (shape_t *)text; } diff -r 7ca25f18902f -r f3366433eee5 src/shapes.h --- a/src/shapes.h Fri Oct 31 00:12:17 2008 +0800 +++ b/src/shapes.h Fri Oct 31 00:14:53 2008 +0800 @@ -9,12 +9,18 @@ #include #include "mb_types.h" +#include "redraw_man.h" /*! \page define_shape How to Define Shapes * - * A shape must include - * - *_new() and *_free() + * A shape implementation must include + * - rdman_shape_*_new() * - clear memory for shape_t member. + * - assign *_free() to \ref shape_t::free. + * - make new object been managed by a redraw manager. + * - call rdman_shape_man() + * - *_free() + * - assigned to \ref shape_t::free. * - *_transform() * - *_draw() * - first member variable of a shape type must be a shape_t. @@ -32,7 +38,7 @@ /*! \defgroup shape_path Shape of Path * @{ */ -extern shape_t *sh_path_new(char *data); +extern shape_t *rdman_shape_path_new(redraw_man_t *rdman, char *data); extern void sh_path_transform(shape_t *shape); extern void sh_path_draw(shape_t *shape, cairo_t *cr); /* @} */ @@ -40,8 +46,10 @@ /*! \defgroup shape_text Shape of Text * @{ */ -extern shape_t *sh_text_new(const char *txt, co_aix x, co_aix y, - co_aix font_size, cairo_font_face_t *face); +extern shape_t *rdman_shape_text_new(redraw_man_t *rdman, + const char *txt, co_aix x, co_aix y, + co_aix font_size, + cairo_font_face_t *face); extern void sh_text_set_text(shape_t *shape, const char *txt); extern void sh_text_transform(shape_t *shape); extern void sh_text_draw(shape_t *shape, cairo_t *cr); @@ -50,8 +58,10 @@ /*! \defgroup shape_rect Shape of Rectangle * @{ */ -extern shape_t *sh_rect_new(co_aix x, co_aix y, co_aix w, co_aix h, - co_aix rx, co_aix ry); +extern shape_t *rdman_shape_rect_new(redraw_man_t *rdman, + co_aix x, co_aix y, + co_aix w, co_aix h, + co_aix rx, co_aix ry); extern void sh_rect_transform(shape_t *shape); extern void sh_rect_draw(shape_t *shape, cairo_t *cr); extern void sh_rect_set(shape_t *shape, co_aix x, co_aix y, diff -r 7ca25f18902f -r f3366433eee5 src/shift.c --- a/src/shift.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/shift.c Fri Oct 31 00:14:53 2008 +0800 @@ -91,6 +91,7 @@ shift->action.stop = mb_shift_stop; shift->action.free = mb_shift_free; + /*! \note mb_shift_new() will add itself to the specified word. */ mb_word_add_action(word, (mb_action_t *)shift); return (mb_action_t *)shift; diff -r 7ca25f18902f -r f3366433eee5 src/timer.c --- a/src/timer.c Fri Oct 31 00:12:17 2008 +0800 +++ b/src/timer.c Fri Oct 31 00:14:53 2008 +0800 @@ -61,7 +61,8 @@ for(visit = STAILQ_HEAD(tman->timers); visit != NULL; visit = STAILQ_NEXT(mb_timer_t, next, visit)) { - if(MB_TIMEVAL_LATER(&visit->tmo, tmo)) + if(MB_TIMEVAL_LATER(&visit->tmo, tmo) || + MB_TIMEVAL_EQ(&visit->tmo, tmo)) break; last = visit; } diff -r 7ca25f18902f -r f3366433eee5 src/tools.h --- a/src/tools.h Fri Oct 31 00:12:17 2008 +0800 +++ b/src/tools.h Fri Oct 31 00:14:53 2008 +0800 @@ -55,13 +55,75 @@ _stailq_cur->field != (elm)) \ _stailq_cur = _stailq_cur->field; \ if(_stailq_cur != NULL) { \ - _stailq_cur->field = elm; \ + _stailq_cur->field = (elm)->field; \ if((q).tail == (elm)) \ (q).tail = _stailq_cur; \ } \ } \ } while(0) +/*! \defgroup darray Dynamic Array + * + * DARRAY is a dynamic sized array/list, it's length is a variable. + * It is extended, automatically, if it is full and more elemnts are + * putted in. + * + * Users of DARRAY must declare a new type to store data. The way to + * declear a new type is to invoke DARRAY() with paramters of name of + * type and type of data to be stored in. The new storage type is named + * with foo_t where foo is the name you pass in. + * + * DARRAY_DEFINE() is inovked to define foo_add() function; foo is name + * of storage type. You can call foo_add() to add a data element + * into a storage object. + * + * Get ith element in a storage object, use + * \code + * obj->ds[i] + * \endcode + * + * To loop over elements in a storage object, us + * \code + * for(i = 0; i < obj->num; i++) { + * v = obj->ds[i]; + * ...... + * } + * \endcode + * @{ + */ +/*! \brief Declare a DARRAY storage type. + * + * \param name is name of storage type. + * \param type is type of data elements that will be stored in. + * + * Type of _t is defined by the macro. It is used to define a + * storage object to contain data elements. + */ +#define DARRAY(name, type) \ + struct _ ## name { \ + int max, num; \ + type *ds; \ + }; \ + typedef struct _ ## name name ## _t +#define DARRAY_DEFINE(name, type) \ + static int name ## _add(name ## _t *da, type v) { \ + type *new_ds; \ + int max; \ + if(da->num >= (da)->max) { \ + max = (da)->max + 32; \ + new_ds = realloc(da->ds, \ + max * sizeof(type)); \ + if(new_ds == NULL) return -1; \ + da->ds = new_ds; \ + da->max = max; \ + } \ + da->ds[da->num++] = v; \ + return 0; \ + } +#define DARRAY_CLEAN(da) do { (da)->num = 0; } while(0) +#define DARRAY_INIT(da) do { (da)->num = (da)->max = 0; (da)->ds = NULL; } +#define DARRAY_DESTROY(da) do { if((da)->ds) free((da)->ds); } while(0) +/* @} */ #include diff -r 7ca25f18902f -r f3366433eee5 tools/mb_c_header.m4 --- a/tools/mb_c_header.m4 Fri Oct 31 00:12:17 2008 +0800 +++ b/tools/mb_c_header.m4 Fri Oct 31 00:14:53 2008 +0800 @@ -48,6 +48,7 @@ typedef struct $1 $1_t; struct $1 { + redraw_man_t *rdman; coord_t *root_coord;] $2[]dnl [}; diff -r 7ca25f18902f -r f3366433eee5 tools/mb_c_source.m4 --- a/tools/mb_c_source.m4 Fri Oct 31 00:12:17 2008 +0800 +++ b/tools/mb_c_source.m4 Fri Oct 31 00:14:53 2008 +0800 @@ -53,7 +53,7 @@ divert[]]) define([S_ADD_LINEAR_PAINT],[ - obj->$1 = paint_linear_new(rdman, $2, $3, $4, $5); + obj->$1 = rdman_paint_linear_new(rdman, $2, $3, $4, $5); ifelse(COUNT($6),0,,[dnl stops = (grad_stop_t *)malloc(sizeof(grad_stop_t) * n_$1_stops); memcpy(stops, $1_stops, sizeof(grad_stop_t) * n_$1_stops); @@ -62,7 +62,7 @@ ]) define([S_ADD_RADIAL_PAINT],[ - obj->$1 = paint_radial_new(rdman, $2, $3, $4); + obj->$1 = rdman_paint_radial_new(rdman, $2, $3, $4); ifelse(COUNT($5),0,,[ stops = (grad_stop_t *)malloc(sizeof(grad_stop_t) * n_$1_stops); memcpy(stops, $1_stops, sizeof(grad_stop_t) * n_$1_stops); @@ -85,12 +85,12 @@ ]]) define([S_ADD_RECT],[[ - obj->$1 = sh_rect_new($2, $3, $4, $5, $6, $7); + obj->$1 = rdman_shape_rect_new(rdman, $2, $3, $4, $5, $6, $7); rdman_add_shape(rdman, obj->$1, obj->$8); ]]) define([S_ADD_PATH],[[ - obj->$1 = sh_path_new("$2"); + obj->$1 = rdman_shape_path_new(rdman, "$2"); rdman_add_shape(rdman, obj->$1, obj->$3); ]]) @@ -99,7 +99,8 @@ ]]) define([S_ADD_TEXT],[[ - obj->$1 = sh_text_new("$2", $3, $4, $5, cairo_get_font_face(rdman->cr)); + obj->$1 = rdman_shape_text_new(rdman, "$2", $3, $4, $5, + cairo_get_font_face(rdman->cr)); rdman_add_shape(rdman, obj->$1, obj->$6); ]]) @@ -112,12 +113,12 @@ ]]) define([S_FILL_SHAPE],[dnl -[ obj->$1_fill = paint_color_new(rdman, $2, $3, $4, $5); +[ obj->$1_fill = rdman_paint_color_new(rdman, $2, $3, $4, $5); rdman_paint_fill(rdman, obj->$1_fill, obj->$1); ]]) define([S_STROKE_SHAPE],[dnl -[ obj->$1_stroke = paint_color_new(rdman, $2, $3, $4, $5); +[ obj->$1_stroke = rdman_paint_color_new(rdman, $2, $3, $4, $5); rdman_paint_stroke(rdman, obj->$1_stroke, obj->$1); ]]) @@ -203,33 +204,33 @@ define([F_ADD_LINEAR_PAINT],[[ stops = paint_linear_stops(obj->$1, 0, NULL); free(stops); - obj->$1->free(obj->$1); + rdman_paint_free(rdman, obj->$1); ]]) define([F_ADD_RADIAL_PAINT],[[ stops = paint_radial_stops(obj->$1, 0, NULL); free(stops); - obj->$1->free(obj->$1); + rdman_paint_free(rdman, obj->$1); ]]) define([F_ADD_PATH],[[ - obj->$1->free(obj->$1); + rdman_shape_free(rdman, obj->$1); ]]) define([F_ADD_RECT],[[ - obj->$1->free(obj->$1); + rdman_shape_free(rdman, obj->$1); ]]) define([F_ADD_TEXT],[[ - obj->$1->free(obj->$1); + rdman_shape_free(rdman, obj->$1); ]]) define([F_FILL_SHAPE],[[ - obj->$1_fill->free(obj->$1_fill); + rdman_paint_free(rdman, obj->$1_fill); ]]) define([F_STROKE_SHAPE],[[ - obj->$1_stroke->free(obj->$1_stroke); + rdman_paint_free(rdman, obj->$1_stroke); ]]) define([CLEAR_VARS],[divert([-1]) @@ -257,6 +258,42 @@ define([SHAPE_MATRIX],) divert[]]) +define([REVERSE_VARS],[divert([-1]) +define([__REV_VAR],[]) +define([PUSH_REV], [ + pushdef([__REV_VAR]) + define([__REV_VAR], ]QUOTE(QUOTE($[]1))[)]) +define([POP_ALL_REV], [dnl +ifelse(__REV_VAR, [], ,[UNQUOTE(__REV_VAR)[]dnl +popdef([__REV_VAR])[]POP_ALL_REV[]])]) +define([RIMPORT], [ + define(]QUOTE($[]1)[, + [PUSH_REV(]]QUOTE(QUOTE($[]1))[[(]QUOTE($[]@)[))]) +]) +RIMPORT([ADD_LINEAR_PAINT]) +RIMPORT([ADD_RADIAL_PAINT]) +RIMPORT([COLOR_STOP]) +RIMPORT([REF_STOPS_RADIAL]) +RIMPORT([REF_STOPS_LINEAR]) +RIMPORT([ADD_PATH]) +RIMPORT([ADD_RECT]) +RIMPORT([ADD_COORD]) +RIMPORT([ADD_TEXT]) +RIMPORT([FILL_SHAPE]) +RIMPORT([STROKE_SHAPE]) +RIMPORT([FILL_SHAPE_WITH_PAINT]) +RIMPORT([STROKE_SHAPE_WITH_PAINT]) +RIMPORT([STROKE_WIDTH]) +RIMPORT([GROUP_HIDE]) +RIMPORT([RECT_HIDE]) +RIMPORT([PATH_HIDE]) +RIMPORT([COORD_TRANSLATE]) +RIMPORT([COORD_MATRIX]) +RIMPORT([SHAPE_TRANSLATE]) +RIMPORT([SHAPE_MATRIX]) +divert[]dnl +]) + define([MADBUTTERFLY],[dnl [#include #include @@ -274,6 +311,7 @@ [ obj = ($1_t *)malloc(sizeof($1_t)); if(obj == NULL) return NULL; + obj->rdman = rdman; ]SETUP_VARS obj->root_coord = rdman_coord_new(rdman, parent_coord); $2 @@ -282,7 +320,16 @@ void $1_free($1_t *obj) { grad_stop_t *stops = NULL; -]CLEAR_VARS[]$2[ + redraw_man_t *rdman; + + rdman = obj->rdman; +]REVERSE_VARS[]dnl +divert([-1])dnl +$2[]dnl +divert[]dnl +CLEAR_VARS[]dnl +POP_ALL_REV[ + rdman_coord_subtree_free(rdman, obj->root_coord); free(obj); } ]dnl