changeset 748:56a5e08cd8af

Make shapes can be removed from the tree
author Thinker K.F. Li <thinker@codemud.net>
date Wed, 25 Aug 2010 18:46:47 +0800
parents d2f2ed27b84d
children ed59e659a202
files nodejs/coord.cc nodejs/shapes.cc nodejs/shapes.m4 nodejs/testcase.js
diffstat 4 files changed, 75 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/nodejs/coord.cc	Wed Aug 25 18:22:32 2010 +0800
+++ b/nodejs/coord.cc	Wed Aug 25 18:46:47 2010 +0800
@@ -196,6 +196,7 @@
 xnjsmb_coord_add_shape(coord_t *coord, Handle<Object> self,
 			shape_t *shape, const char **err) {
     Handle<Object> js_rt;
+    Persistent<Object> *shape_hdl;
     redraw_man_t *rdman;
     int r;
     
@@ -204,6 +205,11 @@
     r = rdman_add_shape(rdman, shape, coord);
     if(r != 0)
 	*err = "Unknown error";
+
+    /* see \ref jsgc */
+    shape_hdl = (Persistent<Object> *)mb_prop_get(&shape->obj.props,
+						  PROP_JSOBJ);
+    shape_hdl->ClearWeak();
 }
 
 static void
--- a/nodejs/shapes.cc	Wed Aug 25 18:22:32 2010 +0800
+++ b/nodejs/shapes.cc	Wed Aug 25 18:46:47 2010 +0800
@@ -11,6 +11,8 @@
 #define ASSERT(x)
 #endif
 
+#define OK 0
+
 using namespace v8;
 
 /*! \defgroup xnjsmb_shapes JS binding for shapes.
@@ -18,6 +20,29 @@
  *
  * @{
  */
+/*! \brief This function is called when GC collecting a shape.
+ *
+ * It was installed by Persistent<Object>::MakeWeak().
+ */
+static void
+xnjsmb_shape_recycled(Persistent<Value> obj, void *parameter) {
+    Persistent<Object> *self_hdl = (Persistent<Object> *)parameter;
+    Handle<Object> js_rt;
+    redraw_man_t *rdman;
+    shape_t *shape;
+
+    shape = (shape_t *)UNWRAP(*self_hdl);
+    if(shape == NULL)
+	return;
+    
+    WRAP(*self_hdl, NULL);
+
+    js_rt = GET(*self_hdl, "mbrt")->ToObject();
+    rdman = xnjsmb_rt_rdman(js_rt);
+    rdman_shape_changed(rdman, shape);
+    rdman_shape_free(rdman, shape);
+}
+
 static void
 xnjsmb_shape_mod(Handle<Object> self, shape_t *sh) {
     Persistent<Object> *self_hdl;
@@ -28,6 +53,8 @@
     self_hdl = new Persistent<Object>();
     *self_hdl = Persistent<Object>::New(self);
     mb_prop_set(&sh->obj.props, PROP_JSOBJ, self_hdl);
+
+    self_hdl->MakeWeak(self_hdl, xnjsmb_shape_recycled);
 }
 
 static void
@@ -102,6 +129,31 @@
 }
 
 static void
+xnjsmb_shape_remove(shape_t *sh, Handle<Object> self) {
+    Handle<Object> js_rt;
+    redraw_man_t *rdman;
+    Persistent<Object> *self_hdl;
+    int r;
+
+    self_hdl = (Persistent<Object> *)mb_prop_get(&sh->obj.props,
+						 PROP_JSOBJ);
+    
+    SET(*self_hdl, "valid", Boolean::New(0));
+    WRAP(*self_hdl, NULL);
+
+    js_rt = GET(*self_hdl, "mbrt")->ToObject();
+    ASSERT(js_rt != NULL);
+    rdman = xnjsmb_rt_rdman(js_rt);
+    
+    rdman_shape_changed(rdman, sh);
+    r = rdman_shape_free(rdman, sh);
+    if(r != OK)
+	THROW_noret("Can not free a shape for unknown reason");
+
+    delete self_hdl;
+}
+
+static void
 xnjsmb_sh_rect_set(shape_t *sh, Handle<Object> self, float x, float y,
 		   float w, float h, float rx, float ry) {
     Handle<Object> rt;
--- a/nodejs/shapes.m4	Wed Aug 25 18:22:32 2010 +0800
+++ b/nodejs/shapes.m4	Wed Aug 25 18:46:47 2010 +0800
@@ -5,9 +5,11 @@
 		 [xnjsmb_shape_stroke_width_get],
 		 [xnjsmb_shape_stroke_width_set])],
        [METHOD([show], [sh_show], (), 0, []),
-        METHOD([hide], [sh_hide], (), 0, [])])
+        METHOD([hide], [sh_hide], (), 0, []),
+	METHOD([remove], [xnjsmb_shape_remove], (SELF), 0, [])])
 
-STRUCT([path], [shape_t], [], [], (([INHERIT], [shape])))
+STRUCT([path], [shape_t], [], [],
+       (([INHERIT], [shape]), ([STMOD], [xnjsmb_shape_mod])))
 
 STRUCT([stext], [shape_t], [],
        [METHOD([set_text], [sh_stext_set_text], (STR([txt])), 1, []),
--- a/nodejs/testcase.js	Wed Aug 25 18:22:32 2010 +0800
+++ b/nodejs/testcase.js	Wed Aug 25 18:46:47 2010 +0800
@@ -44,15 +44,25 @@
 
 /* test removing a coord */
 var rm_coord = mb_rt.coord_new(root);
-var rm_rect = mb_rt.rect_new(150, 150, 50, 50, 10, 10);
-paint.fill(rm_rect);
-rm_coord.add_shape(rm_rect);
+var rm_rect1 = mb_rt.rect_new(150, 150, 50, 50, 10, 10);
+paint.fill(rm_rect1);
+rm_coord.add_shape(rm_rect1);
+var rm_rect2 = mb_rt.rect_new(100, 150, 50, 50, 10, 10);
+paint.fill(rm_rect2);
+rm_coord.add_shape(rm_rect2);
 setTimeout(function() {
 	rm_coord.remove();
 	mb_rt.redraw_changed();
 	mb_rt.flush();
     }, 3000);
 
+/* test removing a shape */
+setTimeout(function() {
+	rm_rect1.remove();
+	mb_rt.redraw_changed();
+	mb_rt.flush();
+    }, 2000);
+
 /* Moving a path */
 sys.puts(mb_rt.path_new);
 var path = mb_rt.path_new("m 100,50 L 120,50 L 200,150 L 180,150 z");