changeset 873:881efcd8a18f abs_n_rel_center

Merge from default branch
author Thinker K.F. Li <thinker@codemud.net>
date Fri, 24 Sep 2010 16:06:42 +0800
parents 3ce9daa9558b (current diff) bcc63b20d5c6 (diff)
children ec8d7e9c9642
files nodejs/mbapp.js nodejs/svg.js nodejs/testdesktop.js src/redraw_man.c
diffstat 13 files changed, 679 insertions(+), 153 deletions(-) [+]
line wrap: on
line diff
--- a/include/mb_X_supp.h	Tue Sep 21 00:40:36 2010 +0800
+++ b/include/mb_X_supp.h	Fri Sep 24 16:06:42 2010 +0800
@@ -27,7 +27,9 @@
 
 extern void X_MB_handle_connection(void *rt);
 extern void *X_MB_new(const char *display_name, int w, int h);
+extern void *X_MB_new_with_win(Display *display, Window win);
 extern void X_MB_free(void *xmb_rt);
+extern void X_MB_free_keep_win(void *rt);
 
 extern subject_t *X_MB_kbevents(void *xmb_rt);
 extern redraw_man_t *X_MB_rdman(void *xmb_rt);
--- a/include/mb_redraw_man.h	Tue Sep 21 00:40:36 2010 +0800
+++ b/include/mb_redraw_man.h	Fri Sep 24 16:06:42 2010 +0800
@@ -50,9 +50,14 @@
     elmpool_t *geo_pool;
     elmpool_t *coord_pool;
     elmpool_t *shnode_pool;
+    elmpool_t *sh_path_pool;
+    elmpool_t *sh_rect_pool;
     elmpool_t *observer_pool;
     elmpool_t *subject_pool;
     elmpool_t *paint_color_pool;
+    elmpool_t *paint_linear_pool;
+    elmpool_t *paint_radial_pool;
+    elmpool_t *paint_image_pool;
     elmpool_t *pent_pool;
     elmpool_t *coord_canvas_pool;
 
--- a/nodejs/X_supp_njs.c	Tue Sep 21 00:40:36 2010 +0800
+++ b/nodejs/X_supp_njs.c	Fri Sep 24 16:06:42 2010 +0800
@@ -113,6 +113,22 @@
     free(rt);
 }
 
+/*! \brief Free njs_runtime_t.
+ */
+void
+X_njs_MB_free_keep_win(njs_runtime_t *rt) {
+    /*
+     * stop IO and timer watcher
+     */
+    if(rt->enable_io)
+	ev_io_stop(&rt->iowatcher);
+    if(rt->enable_timer)
+	ev_timer_stop(&rt->tmwatcher);
+
+    X_MB_free_keep_win(rt->xrt);
+    free(rt);
+}
+
 int
 X_njs_MB_flush(njs_runtime_t *rt) {
     void *xrt = rt->xrt;
@@ -141,6 +157,48 @@
     return rt;
 }
 
+/*! \brief Create a njs_runtime_t for an existed window.
+ *
+ * The njs_runtime_t created by this function must be free by
+ * X_njs_MB_free_keep_win().
+ */
+njs_runtime_t *
+X_njs_MB_new_with_win(void *display, long win) {
+    njs_runtime_t *rt;
+    void *xrt;
+
+    rt = (njs_runtime_t *)malloc(sizeof(njs_runtime_t));
+    ASSERT(rt != NULL);
+
+    xrt = X_MB_new_with_win((Display *)display, win);
+
+    rt->xrt = xrt;
+    rt->enable_io = 0;
+    rt->enable_timer = 0;	/* no timer, now */
+
+    return rt;
+}
+
+/*! \brief Pass a X event to X runtime.
+ */
+void
+X_njs_MB_handle_single_event(njs_runtime_t *rt, void *evt) {
+    void *xrt = rt->xrt;
+    extern void _X_MB_handle_single_event(void *rt, void *evt);
+
+    _X_MB_handle_single_event(xrt, evt);
+}
+
+/*! \brief Called at end of an iteration of event loop.
+ */
+void
+X_njs_MB_no_more_event(njs_runtime_t *rt) {
+    void *xrt = rt->xrt;
+    extern void _X_MB_no_more_event(void *rt);
+
+    _X_MB_no_more_event(xrt);
+}
+
 /*! \brief Get X runtime that is backend of this njs runtime.
  */
 void *
--- a/nodejs/X_supp_njs.h	Tue Sep 21 00:40:36 2010 +0800
+++ b/nodejs/X_supp_njs.h	Fri Sep 24 16:06:42 2010 +0800
@@ -16,7 +16,11 @@
 extern void X_njs_MB_init_handle_connection(njs_runtime_t *rt);
 extern void X_njs_MB_free(njs_runtime_t *rt);
 extern njs_runtime_t *X_njs_MB_new(char *display_name, int w, int h);
+extern void X_njs_MB_free_keep_win(njs_runtime_t *rt);
+extern njs_runtime_t *X_njs_MB_new_with_win(void *display, long win);
 extern int X_njs_MB_flush(njs_runtime_t *rt);
+extern void X_njs_MB_handle_single_event(njs_runtime_t *rt, void *evt);
+extern void X_njs_MB_no_more_event(njs_runtime_t *rt);
 extern void *_X_njs_MB_get_X_runtime(njs_runtime_t *rt);
 
 #define X_njs_MB_kbevents(rt) X_MB_kbevents((rt)->xrt)
--- a/nodejs/mbapp.js	Tue Sep 21 00:40:36 2010 +0800
+++ b/nodejs/mbapp.js	Fri Sep 24 16:06:42 2010 +0800
@@ -138,7 +138,32 @@
 	}
 }
 
+var app_with_win = function(display, win) {
+    var self = this;
+    var mb_rt;
+    var background;
+    var paint;
+
+    if(typeof display == "undefined" || typeof win == "undefined")
+	throw "Invalid argument";
+    
+    mb_rt = this.mb_rt = new mbfly.mb_rt_with_win(display, win);
+    background = mb_rt.rect_new(0, 0, 720, 480, 0, 0);
+    paint = mb_rt.paint_color_new(1, 1, 1, 1);
+    paint.fill(background);
+    mb_rt.root.add_shape(background);
+
+    this.mb_rt.kbevents.
+	add_event_observer(exports.EVT_KB_PRESS,
+			   function(evt) { self.KeyPress(evt); });
+    this.keymap = {};
+    this.onKeyPress = null;
+}
+
+app_with_win.prototype = app.prototype;
+
 exports.app=app;
+exports.app_with_win = app_with_win;
 
 // Put all key definition here
 exports.KEY_LEFT = 0xff51;
--- a/nodejs/mbfly_njs.cc	Tue Sep 21 00:40:36 2010 +0800
+++ b/nodejs/mbfly_njs.cc	Fri Sep 24 16:06:42 2010 +0800
@@ -58,6 +58,16 @@
     rdman_redraw_all(rdman);
 }
 
+static void
+xnjsmb_handle_single_event(njs_runtime_t *rt, void *evt) {
+    X_njs_MB_handle_single_event(rt, evt);
+}
+
+static void
+xnjsmb_no_more_event(njs_runtime_t *rt) {
+    X_njs_MB_no_more_event(rt);
+}
+
 static njs_runtime_t *
 _X_njs_MB_new(Handle<Object> self, char *display_name,
 	      int width, int height) {
@@ -80,6 +90,27 @@
     return obj;
 }
 
+static njs_runtime_t *
+_X_njs_MB_new_with_win(Handle<Object> self, void *display,
+		       long win) {
+    njs_runtime_t *obj;
+    subject_t *subject;
+    Handle<Value> subject_o;
+
+    obj = X_njs_MB_new_with_win(display, win);
+    WRAP(self, obj);		/* mkroot need a wrapped object, but
+				 * it is wrapped after returning of
+				 * this function.  So, we wrap it
+				 * here. */
+    xnjsmb_coord_mkroot(self);
+
+    subject = X_njs_MB_kbevents(obj);
+    subject_o = export_xnjsmb_auto_subject_new(subject);
+    SET(self, "kbevents", subject_o);
+
+    return obj;
+}
+
 /*! \defgroup njs_template_cb Callback functions for v8 engine and nodejs.
  *
  * @{
@@ -138,6 +169,8 @@
      * Initialize template for MadButterfly runtime objects.
      */
     xnjsmb_auto_mb_rt_init();
+    xnjsmb_auto_mb_rt_display_init();
+    xnjsmb_auto_mb_rt_with_win_init();
 
     /*
      * Add properties to mb_rt templates for other modules.
@@ -150,6 +183,8 @@
 
     target->Set(String::New("mb_rt"),
 		xnjsmb_auto_mb_rt_temp->GetFunction());
+    target->Set(String::New("mb_rt_with_win"),
+		xnjsmb_auto_mb_rt_with_win_temp->GetFunction());
 }
 
 /* @} */
--- a/nodejs/mbfly_njs.m4	Tue Sep 21 00:40:36 2010 +0800
+++ b/nodejs/mbfly_njs.m4	Fri Sep 24 16:06:42 2010 +0800
@@ -39,6 +39,27 @@
 	METHOD([paint_radial_new], [xnjsmb_paint_radial_new],
 	       (NUMBER(cx), NUMBER(cy), NUMBER(r), ERR), 3,
 	       [OBJ([paint_radial], [paint_t])],
-	       (([MOD], [xnjsmb_mb_rt_objs_mod])))],
+	       (([MOD], [xnjsmb_mb_rt_objs_mod]))),
+	METHOD([handle_single_event], [xnjsmb_handle_single_event],
+	       (OBJ([evt], [event], [void])), 1, []),
+	METHOD([no_more_event], [xnjsmb_no_more_event],
+	       (), 0, [])],
 	((CTOR, ([_X_njs_MB_new], (SELF, STR(display_name), INT(width), INT(height)), 3)))dnl
 )
+dnl
+dnl
+dnl
+STRUCT([mb_rt_display], [void], [],
+       [],
+       ())dnl
+dnl
+dnl Function to create mb_rt for an existed window.
+dnl
+STRUCT([mb_rt_with_win], [njs_runtime_t], [],
+       [],
+       ((CTOR, ([_X_njs_MB_new_with_win],dnl
+       	        (SELF, OBJ([display], [mb_rt_display], [void]),dnl
+		 INT([window])),dnl
+		 2)),dnl
+        ([INHERIT], [mb_rt]))dnl
+)
--- a/src/X_main.c	Tue Sep 21 00:40:36 2010 +0800
+++ b/src/X_main.c	Fri Sep 24 16:06:42 2010 +0800
@@ -210,7 +210,7 @@
     tman = mb_tman_new();
     if(tman) {
 	/* Prepare an animation program. */
-	progm = mb_progm_new(10, &rdman);
+	progm = mb_progm_new(30, &rdman);
 
 	MB_TIMEVAL_SET(&start, 0, 0);
 	MB_TIMEVAL_SET(&playing, 1, 0);
@@ -237,6 +237,166 @@
 	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
 	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
 
+	MB_TIMEVAL_SET(&start, 5, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, 20, coord1, word);
+	act = mb_shift_new(0, -20, coord2, word);
+	act = mb_chgcolor_new(1, 0, 0, 1, fill1, word);
+	act = mb_chgcolor_new(0, 0, 1, 1, fill2, word);
+	act = mb_visibility_new(VIS_HIDDEN, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 7, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, -20, coord1, word);
+	act = mb_shift_new(0, 20, coord2, word);
+	act = mb_chgcolor_new(0, 1, 0, 0.5, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
+	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 9, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, 20, coord1, word);
+	act = mb_shift_new(0, -20, coord2, word);
+	act = mb_chgcolor_new(0, 0, 1, 1, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 1, fill2, word);
+	act = mb_visibility_new(VIS_HIDDEN, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 11, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, -20, coord1, word);
+	act = mb_shift_new(0, 20, coord2, word);
+	act = mb_chgcolor_new(0, 1, 0, 0.5, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
+	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 13, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, 20, coord1, word);
+	act = mb_shift_new(0, -20, coord2, word);
+	act = mb_chgcolor_new(0, 0, 1, 1, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 1, fill2, word);
+	act = mb_visibility_new(VIS_HIDDEN, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 15, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, -20, coord1, word);
+	act = mb_shift_new(0, 20, coord2, word);
+	act = mb_chgcolor_new(0, 1, 0, 0.5, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
+	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 17, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, 20, coord1, word);
+	act = mb_shift_new(0, -20, coord2, word);
+	act = mb_chgcolor_new(0, 0, 1, 1, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 1, fill2, word);
+	act = mb_visibility_new(VIS_HIDDEN, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 19, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, -20, coord1, word);
+	act = mb_shift_new(0, 20, coord2, word);
+	act = mb_chgcolor_new(0, 1, 0, 0.5, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
+	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 21, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, 20, coord1, word);
+	act = mb_shift_new(0, -20, coord2, word);
+	act = mb_chgcolor_new(0, 0, 1, 1, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 1, fill2, word);
+	act = mb_visibility_new(VIS_HIDDEN, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 23, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, -20, coord1, word);
+	act = mb_shift_new(0, 20, coord2, word);
+	act = mb_chgcolor_new(0, 1, 0, 0.5, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
+	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 25, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, 20, coord1, word);
+	act = mb_shift_new(0, -20, coord2, word);
+	act = mb_chgcolor_new(0, 0, 1, 1, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 1, fill2, word);
+	act = mb_visibility_new(VIS_HIDDEN, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 27, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, -20, coord1, word);
+	act = mb_shift_new(0, 20, coord2, word);
+	act = mb_chgcolor_new(0, 1, 0, 0.5, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
+	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 29, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, 20, coord1, word);
+	act = mb_shift_new(0, -20, coord2, word);
+	act = mb_chgcolor_new(0, 0, 1, 1, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 1, fill2, word);
+	act = mb_visibility_new(VIS_HIDDEN, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 31, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, -20, coord1, word);
+	act = mb_shift_new(0, 20, coord2, word);
+	act = mb_chgcolor_new(0, 1, 0, 0.5, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
+	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 33, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, 20, coord1, word);
+	act = mb_shift_new(0, -20, coord2, word);
+	act = mb_chgcolor_new(0, 0, 1, 1, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 1, fill2, word);
+	act = mb_visibility_new(VIS_HIDDEN, coord3, word);
+
+	MB_TIMEVAL_SET(&start, 35, 0);
+	MB_TIMEVAL_SET(&playing, 2, 0);
+	word = mb_progm_next_word(progm, &start, &playing);
+
+	act = mb_shift_new(0, -20, coord1, word);
+	act = mb_shift_new(0, 20, coord2, word);
+	act = mb_chgcolor_new(0, 1, 0, 0.5, fill1, word);
+	act = mb_chgcolor_new(1, 0, 0, 0.5, fill2, word);
+	act = mb_visibility_new(VIS_VISIBLE, coord3, word);
+
 	/* Start playing the program. */
 	gettimeofday(&tv, NULL);
 	MB_TIMEVAL_SET(&mbtv, tv.tv_sec, tv.tv_usec);
--- a/src/X_supp.c	Tue Sep 21 00:40:36 2010 +0800
+++ b/src/X_supp.c	Fri Sep 24 16:06:42 2010 +0800
@@ -43,6 +43,7 @@
     mb_eventcb_t f;
     void *arg;
 }  monitor_t;
+
 struct _X_MB_runtime {
     Display *display;
     Window win;
@@ -68,6 +69,16 @@
     XImage *ximage;
     XShmSegmentInfo shminfo;
 #endif
+
+    /*
+     * 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 */
 };
 
 #ifdef XSHM
@@ -213,26 +224,184 @@
     subject_notify(subject, (event_t *)&mouse_event);
 }
 
-/*! \brief Dispatch all X events in the queue.
+/*! \brief Handle motion event.
  */
-static void handle_x_event(X_MB_runtime_t *rt) {
-    Display *display = rt->display;
+static void
+handle_motion_event(X_MB_runtime_t *rt) {
     redraw_man_t *rdman = rt->rdman;
-    XEvent evt, peek_evt;
+    int x, y;
+    int state;
+    shape_t *shape;
+    coord_t *root;
+    int in_stroke;
+    
+    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_MB_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_MB_runtime_t *rt, XEvent *evt) {
+    redraw_man_t *rdman = rt->rdman;
     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;
+    int x, y, w, h;
 
     shape_t *shape;
-    coord_t *root;
 
     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_MB_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) {
+    Display *display = rt->display;
+    XEvent evt;
     int r;
 
     /* XXX: For some unknown reason, it causes a segmentation fault to
@@ -244,123 +413,10 @@
 	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;
-		}
-	    }
-#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;
-	}
+	handle_single_x_event(rt, &evt);
     }
-    if(eflag) {
-	rdman_redraw_area(rdman, ex1, ey1, (ex2 - ex1), (ey2 - ey1));
-	eflag = 0;
-    }
+    no_more_event(rt);
+    
 #ifdef XSHM
     XSHM_update(rt);
 #endif
@@ -616,7 +672,7 @@
  *   - visual
  */
 static int
-X_MB_init_with_win(X_MB_runtime_t *xmb_rt) {
+X_MB_init_with_win_internal(X_MB_runtime_t *xmb_rt) {
     mb_img_ldr_t *img_ldr;
     int w, h;
 
@@ -673,8 +729,8 @@
  * It setups a runtime environment to run MadButterfly with Xlib.
  * Users should specify width and height of the opening window.
  */
-static int X_MB_init(const char *display_name,
-	      int w, int h, X_MB_runtime_t *xmb_rt) {
+static int X_MB_init(X_MB_runtime_t *xmb_rt, const char *display_name,
+		     int w, int h) {
     int r;
 
     memset(xmb_rt, 0, sizeof(X_MB_runtime_t));
@@ -686,7 +742,35 @@
     if(r != OK)
 	return ERR;
 
-    r = X_MB_init_with_win(xmb_rt);
+    r = X_MB_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_MB_destroy_keep_win().
+ */
+static int
+X_MB_init_with_win(X_MB_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_MB_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_MB_init_with_win_internal(xmb_rt);
 
     return r;
 }
@@ -721,6 +805,28 @@
     X_kb_destroy(&xmb_rt->kbinfo);
 }
 
+/*! \brief Destroy a MadButterfly runtime initialized with
+ *	X_MB_init_with_win().
+ *
+ * Destroying a runtime with this function prevent the window and
+ * display associated with the runtime being closed.
+ */
+static void
+X_MB_destroy_keep_win(X_MB_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_MB_destroy(xmb_rt);
+    
+    xmb_rt->display = display;
+    xmb_rt->win = win;
+}
+
 void *X_MB_new(const char *display_name, int w, int h) {
     X_MB_runtime_t *rt;
     int r;
@@ -729,7 +835,29 @@
     if(rt == NULL)
 	return NULL;
 
-    r = X_MB_init(display_name, w, h, rt);
+    r = X_MB_init(rt, display_name, w, h);
+    if(r != OK) {
+	free(rt);
+	return NULL;
+    }
+
+    return rt;
+}
+
+/*! \brief Create a new runtime for existed window for X.
+ *
+ * The object returned by this function must be free with
+ * X_MB_free_keep_win() to prevent the window from closed.
+ */
+void *X_MB_new_with_win(Display *display, Window win) {
+    X_MB_runtime_t *rt;
+    int r;
+
+    rt = O_ALLOC(X_MB_runtime_t);
+    if(rt == NULL)
+	return NULL;
+
+    r = X_MB_init_with_win(rt, display, win);
     if(r != OK) {
 	free(rt);
 	return NULL;
@@ -743,6 +871,14 @@
     free(rt);
 }
 
+/*! \brief Free runtime created with X_MB_new_with_win().
+ */
+void
+X_MB_free_keep_win(void *rt) {
+    X_MB_destroy_keep_win((X_MB_runtime_t *) rt);
+    free(rt);
+}
+
 subject_t *X_MB_kbevents(void *rt) {
     X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt;
     return xmb_rt->kbinfo.kbevents;
@@ -854,4 +990,22 @@
     return XFlush(xmb_rt->display);
 }
 
+/*! \brief Handle single X event.
+ */
+void
+_X_MB_handle_single_event(void *rt, void *evt) {
+    X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *)rt;
+    
+    handle_single_x_event(xmb_rt, (XEvent *)evt);
+}
+
+/*! \brief Called at end of an iteration of X event loop.
+ */
+void
+_X_MB_no_more_event(void *rt) {
+    X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *)rt;
+    
+    no_more_event(xmb_rt);
+}
+
 /* @} */
--- a/src/paint.c	Tue Sep 21 00:40:36 2010 +0800
+++ b/src/paint.c	Fri Sep 24 16:06:42 2010 +0800
@@ -82,6 +82,8 @@
 
 #define LIF_DIRTY 0x1
 
+int _paint_linear_size = sizeof(paint_linear_t);
+
 static void paint_linear_prepare(paint_t *paint, mbe_t *cr) {
     paint_linear_t *linear = (paint_linear_t *)paint;
     mbe_pattern_t *ptn;
@@ -107,7 +109,7 @@
     if(linear->ptn)
 	mbe_pattern_destroy(linear->ptn);
     paint_destroy(paint);
-    free(paint);
+    elmpool_elm_free(rdman->paint_linear_pool, linear);
 }
 
 paint_t *rdman_paint_linear_new(redraw_man_t *rdman,
@@ -115,7 +117,7 @@
 				co_aix x2, co_aix y2) {
     paint_linear_t *linear;
 
-    linear = (paint_linear_t *)malloc(sizeof(paint_linear_t));
+    linear = (paint_linear_t *)elmpool_elm_alloc(rdman->paint_linear_pool);
     if(linear == NULL)
 	return NULL;
 
@@ -170,6 +172,8 @@
 
 #define RDF_DIRTY 0x1
 
+int _paint_radial_size = sizeof(paint_radial_t);
+
 static void paint_radial_prepare(paint_t *paint, mbe_t *cr) {
     paint_radial_t *radial = (paint_radial_t *)paint;
     mbe_pattern_t *ptn;
@@ -193,14 +197,14 @@
     if(radial->ptn)
 	mbe_pattern_destroy(radial->ptn);
     paint_destroy(paint);
-    free(paint);
+    elmpool_elm_free(rdman->paint_radial_pool, radial);
 }
 
 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);
+    radial = elmpool_elm_alloc(rdman->paint_radial_pool);
     if(radial == NULL)
 	return NULL;
 
@@ -249,6 +253,8 @@
     mbe_pattern_t *ptn;
 } paint_image_t;
 
+int _paint_image_size = sizeof(paint_image_t);
+
 static
 void paint_image_prepare(paint_t *paint, mbe_t *cr) {
     paint_image_t *paint_img = (paint_image_t *)paint;
@@ -267,7 +273,7 @@
     img_data = paint_img->img;
     MB_IMG_DATA_FREE(img_data);
     paint_destroy(&paint_img->paint);
-    free(paint);
+    elmpool_elm_free(rdman->paint_image_pool, paint_img);
 }
 
 /*! \brief Create an image painter.
@@ -281,7 +287,7 @@
 			       mb_img_data_t *img) {
     paint_image_t *paint;
 
-    paint = O_ALLOC(paint_image_t);
+    paint = elmpool_elm_alloc(rdman->paint_image_pool);
     if(paint == NULL)
 	return NULL;
 
@@ -295,7 +301,7 @@
 						      img->stride);
     if(paint->surf == NULL) {
 	paint_destroy(&paint->paint);
-	free(paint);
+	elmpool_elm_free(rdman->paint_image_pool, paint);
 	return NULL;
     }
 
@@ -303,7 +309,7 @@
     if(paint->ptn == NULL) {
 	paint_destroy(&paint->paint);
 	mbe_surface_destroy(paint->surf);
-	free(paint);
+	elmpool_elm_free(rdman->paint_image_pool, paint);
 	return NULL;
     }
 
--- a/src/redraw_man.c	Tue Sep 21 00:40:36 2010 +0800
+++ b/src/redraw_man.c	Fri Sep 24 16:06:42 2010 +0800
@@ -644,7 +644,12 @@
 
 int redraw_man_init(redraw_man_t *rdman, mbe_t *cr, mbe_t *backend) {
     extern void redraw_man_destroy(redraw_man_t *rdman);
+    extern int _sh_path_size;
+    extern int _sh_rect_size;
     extern int _paint_color_size;
+    extern int _paint_linear_size;
+    extern int _paint_radial_size;
+    extern int _paint_image_size;
     observer_t *addrm_ob;
     extern void addrm_monitor_hdlr(event_t *evt, void *arg);
 
@@ -658,9 +663,14 @@
     rdman->geo_pool = elmpool_new(sizeof(geo_t), 128);
     rdman->coord_pool = elmpool_new(sizeof(coord_t), 16);
     rdman->shnode_pool = elmpool_new(sizeof(shnode_t), 16);
+    rdman->sh_path_pool = elmpool_new(_sh_path_size, 16);
+    rdman->sh_rect_pool = elmpool_new(_sh_rect_size, 16);
     rdman->observer_pool = elmpool_new(sizeof(observer_t), 32);
     rdman->subject_pool = elmpool_new(sizeof(subject_t), 32);
     rdman->paint_color_pool = elmpool_new(_paint_color_size, 64);
+    rdman->paint_linear_pool = elmpool_new(_paint_linear_size, 64);
+    rdman->paint_radial_pool = elmpool_new(_paint_radial_size, 64);
+    rdman->paint_image_pool = elmpool_new(_paint_image_size, 64);
     rdman->pent_pool = elmpool_new(sizeof(mb_prop_entry_t), 128);
     rdman->coord_canvas_pool = elmpool_new(sizeof(coord_canvas_info_t), 16);
     if(!(rdman->geo_pool && rdman->coord_pool && rdman->shnode_pool &&
@@ -725,12 +735,22 @@
 	elmpool_free(rdman->coord_pool);
     if(rdman->shnode_pool)
 	elmpool_free(rdman->shnode_pool);
+    if(rdman->sh_path_pool)
+	elmpool_free(rdman->sh_path_pool);
+    if(rdman->sh_rect_pool)
+	elmpool_free(rdman->sh_rect_pool);
     if(rdman->observer_pool)
 	elmpool_free(rdman->observer_pool);
     if(rdman->subject_pool)
 	elmpool_free(rdman->subject_pool);
     if(rdman->paint_color_pool)
 	elmpool_free(rdman->paint_color_pool);
+    if(rdman->paint_linear_pool)
+	elmpool_free(rdman->paint_linear_pool);
+    if(rdman->paint_radial_pool)
+	elmpool_free(rdman->paint_radial_pool);
+    if(rdman->paint_image_pool)
+	elmpool_free(rdman->paint_image_pool);
     if(rdman->pent_pool)
 	elmpool_free(rdman->pent_pool);
     if(rdman->coord_canvas_pool)
@@ -784,9 +804,14 @@
     elmpool_free(rdman->coord_pool);
     elmpool_free(rdman->geo_pool);
     elmpool_free(rdman->shnode_pool);
+    elmpool_free(rdman->sh_path_pool);
+    elmpool_free(rdman->sh_rect_pool);
     elmpool_free(rdman->observer_pool);
     elmpool_free(rdman->subject_pool);
     elmpool_free(rdman->paint_color_pool);
+    elmpool_free(rdman->paint_linear_pool);
+    elmpool_free(rdman->paint_radial_pool);
+    elmpool_free(rdman->paint_image_pool);
     elmpool_free(rdman->pent_pool);
     elmpool_free(rdman->coord_canvas_pool);
 
@@ -1368,7 +1393,7 @@
  */
 static int
 compute_area(coord_t *coord) {
-    static co_aix (*poses)[2];
+    static co_aix (*poses)[2] = NULL;
     static int max_poses = 0;
     geo_t *geo;
     int cnt, pos_cnt;
@@ -1379,7 +1404,8 @@
     }
 
     if(max_poses < (cnt * 2)) {
-	free(poses);
+	if(poses)
+	    free(poses);
 	max_poses = cnt * 2;
 	poses = (co_aix (*)[2])malloc(sizeof(co_aix [2]) * max_poses);
 	if(poses == NULL)
--- a/src/shape_path.c	Tue Sep 21 00:40:36 2010 +0800
+++ b/src/shape_path.c	Fri Sep 24 16:06:42 2010 +0800
@@ -25,9 +25,13 @@
     int float_arg_len;
     char *user_data;
     char *dev_data;		/* device space data */
+    
+    redraw_man_t *rdman;	/*!< \brief This is used by sh_path_free() */
 } sh_path_t;
 #define RESERVED_AIXS sizeof(co_aix[2])
 
+int _sh_path_size = sizeof(sh_path_t);
+
 #define ASSERT(x)
 #define SKIP_SPACE(x) while(*(x) && (isspace(*(x)) || *(x) == ',')) { (x)++; }
 #define SKIP_NUM(x)					\
@@ -47,6 +51,20 @@
 #ifdef UNITTEST
 #undef rdman_shape_man
 #define rdman_shape_man(x, y)
+
+#undef elmpool_elm_alloc
+#define elmpool_elm_alloc(pool) _elmpool_elm_alloc(pool)
+static void *
+_elmpool_elm_alloc(void *dummy) {
+    return malloc(sizeof(sh_path_t));
+}
+
+#undef elmpool_elm_free
+#define elmpool_elm_free(pool, elm) _elmpool_elm_free(pool, elm)
+static void
+_elmpool_elm_free(void *pool, void *elm) {
+    free(elm);
+}
 #endif
 
 /* ============================================================
@@ -382,7 +400,7 @@
     mb_obj_destroy(path);
     if(path->user_data)
 	free(path->user_data);
-    free(path);
+    elmpool_elm_free(path->rdman->sh_path_pool, path);
 }
 
 /*! \brief Count number of arguments.
@@ -800,7 +818,7 @@
     cmd_cnt = (cmd_cnt + 3) & ~0x3;
 
     /*! \todo Use elmpool to manage sh_path_t objects. */
-    path = (sh_path_t *)malloc(sizeof(sh_path_t));
+    path = (sh_path_t *)elmpool_elm_alloc(rdman->sh_path_pool);
     /*! \todo Remove this memset()? */
     memset(&path->shape, 0, sizeof(shape_t));
     mb_obj_init(path, MBO_PATH);
@@ -812,7 +830,7 @@
 	sizeof(co_aix) * float_arg_cnt;
     path->user_data = (char *)malloc(msz * 2);
     if(path->user_data == NULL) {
-	free(path);
+	elmpool_elm_free(rdman->sh_path_pool, path);
 	return NULL;
     }
 
@@ -821,12 +839,13 @@
     r = sh_path_cmd_arg_fill(data, path);
     if(r == ERR) {
 	free(path->user_data);
-	free(path);
+	elmpool_elm_free(rdman->sh_path_pool, path);
 	return NULL;
     }
     memcpy(path->dev_data, path->user_data, msz);
 
     path->shape.free = sh_path_free;
+    path->rdman = rdman;
 
     rdman_shape_man(rdman, (shape_t *)path);
 
@@ -843,7 +862,7 @@
     int cmd_cnt = strlen(commands);
 
     /*! \todo Use elmpool to manage sh_path_t objects. */
-    path = (sh_path_t *)malloc(sizeof(sh_path_t));
+    path = (sh_path_t *)elmpool_elm_alloc(rdman->sh_path_pool);
     /*! \todo Remove this memset()? */
     memset(&path->shape, 0, sizeof(shape_t));
     mb_obj_init(path, MBO_PATH);
@@ -855,7 +874,7 @@
 	sizeof(co_aix) * float_arg_cnt;
     path->user_data = (char *)malloc(msz * 2);
     if(path->user_data == NULL) {
-	free(path);
+	elmpool_elm_free(rdman->sh_path_pool, path);
 	return NULL;
     }
 
@@ -867,6 +886,7 @@
     memcpy(path->dev_data, path->user_data, msz);
 
     path->shape.free = sh_path_free;
+    path->rdman = rdman;
 
     rdman_shape_man(rdman, (shape_t *)path);
 
@@ -1003,8 +1023,9 @@
 void test_rdman_shape_path_new(void) {
     sh_path_t *path;
     co_aix *pnts;
+    redraw_man_t rdman;
 
-    path = (sh_path_t *)rdman_shape_path_new(NULL, "M 33 25l33 55c 33 87 44 22 55 99L33 77z");
+    path = (sh_path_t *)rdman_shape_path_new(&rdman, "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->pnt_len == 12);
@@ -1032,8 +1053,9 @@
     co_aix *pnts;
     coord_t coord;
     geo_t geo;
+    redraw_man_t rdman;
 
-    path = (sh_path_t *)rdman_shape_path_new(NULL, "M 33 25l33 55C 33 87 44 22 55 99L33 77z");
+    path = (sh_path_t *)rdman_shape_path_new(&rdman, "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->pnt_len == 12);
@@ -1072,9 +1094,10 @@
 
 void test_spaces_head_tail(void) {
     sh_path_t *path;
+    redraw_man_t rdman;
 
     path = (sh_path_t *)
-	rdman_shape_path_new(NULL,
+	rdman_shape_path_new(&rdman,
 			     " M 33 25l33 55C 33 87 44 22 55 99L33 77z ");
     CU_ASSERT(path != NULL);
     sh_path_free((shape_t *)path);
--- a/src/shape_rect.c	Tue Sep 21 00:40:36 2010 +0800
+++ b/src/shape_rect.c	Fri Sep 24 16:06:42 2010 +0800
@@ -12,10 +12,16 @@
     co_aix w, h;
     co_aix rx, ry;
     co_aix poses[12][2];
+
+    redraw_man_t *rdman;	/*!< \brief This is used by sh_rect_free() */
 } sh_rect_t;
 
+int _sh_rect_size = sizeof(sh_rect_t);
+
 static void sh_rect_free(shape_t *shape) {
-    free(shape);
+    sh_rect_t *rect = (sh_rect_t *)shape;
+    
+    elmpool_elm_free(rect->rdman->sh_rect_pool, rect);
 }
 
 shape_t *rdman_shape_rect_new(redraw_man_t *rdman,
@@ -23,7 +29,7 @@
 			      co_aix rx, co_aix ry) {
     sh_rect_t *rect;
 
-    rect = (sh_rect_t *)malloc(sizeof(sh_rect_t));
+    rect = (sh_rect_t *)elmpool_elm_alloc(rdman->sh_rect_pool);
     if(rect == NULL)
 	return NULL;
 
@@ -37,6 +43,7 @@
     rect->rx = rx;
     rect->ry = ry;
     rect->shape.free = sh_rect_free;
+    rect->rdman = rdman;
 
     rdman_shape_man(rdman, (shape_t *)rect);