diff src/redraw_man.c @ 15:c2ce186a5c37

X_main uses rdman_redraw_all()
author Thinker K.F. Li <thinker@branda.to>
date Fri, 01 Aug 2008 01:40:07 +0800
parents d34232f15863
children e17e12b112c4
line wrap: on
line diff
--- a/src/redraw_man.c	Thu Jul 31 17:43:20 2008 +0800
+++ b/src/redraw_man.c	Fri Aug 01 01:40:07 2008 +0800
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <cairo.h>
 #include "mb_types.h"
 #include "shapes.h"
 #include "tools.h"
@@ -12,7 +13,7 @@
 #define OFFSET(type, field) ((void *)&((type *)NULL)->field - (void *)NULL)
 #define SWAP(a, b, t) do { t c;  c = a; a = b; b = c; } while(0)
 
-int redraw_man_init(redraw_man_t *rdman) {
+int redraw_man_init(redraw_man_t *rdman, cairo_t *cr) {
     extern void redraw_man_destroy(redraw_man_t *rdman);
 
     memset(rdman, 0, sizeof(redraw_man_t));
@@ -33,6 +34,8 @@
     rdman->n_coords = 1;
     coord_init(rdman->root_coord, NULL);
 
+    rdman->cr = cr;
+
     return OK;
 }
 
@@ -132,6 +135,7 @@
 	    visit->order = ++next_order;
 	rdman->next_geo_order = next_order;
     }
+    geo->flags |= GEF_DIRTY;
 
     sh_attach_coord(shape, coord);
 
@@ -237,6 +241,7 @@
     int r;
 
     if(rdman->n_dirty_areas >= rdman->max_dirty_areas) {
+	/* every geo object and coord object can contribute 2 areas. */
 	max_dirty_areas = (rdman->n_geos + rdman->n_coords) * 2;
 	r = extend_memblk((void **)&rdman->dirty_areas,
 			  sizeof(area_t *) * rdman->n_dirty_areas,
@@ -320,28 +325,106 @@
     }
 }
 
-static void make_redrawing_members(redraw_man_t *rdman, coord_t *coord) {
-    shape_t *shape;
-
-    for(shape = STAILQ_HEAD(coord->members);
-	shape != NULL;
-	shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) {
-	shape->geo->flags &= ~GEF_DIRTY;
-	add_dirty_geo(rdman, shape->geo);
+static void update_shape_geo(shape_t *shape) {
+    switch(shape->sh_type) {
+    case SHT_PATH:
+	sh_path_transform(shape);
+	break;
     }
 }
 
-static void compute_coord_area(coord_t *coord) {
+static void area_to_positions(area_t *area, co_aix (*poses)[2]) {
+    poses[0][0] = area->x;
+    poses[0][1] = area->y;
+    poses[1][0] = area->x + area->w;
+    poses[1][1] = area->y + area->h;;
 }
 
-static void update_shape_geo(shape_t *shape) {
+static int compute_coord_area(coord_t *coord) {
+    shape_t *shape;
+    geo_t *geo;
+    co_aix (*poses)[2];
+    int cnt, pos_cnt;
+    int i;
+
+    cnt = 0;
+    for(shape = STAILQ_HEAD(coord->members);
+	shape != NULL;
+	shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) {
+	SWAP(shape->geo->cur_area, shape->geo->last_area, area_t *);
+	update_shape_geo(shape);
+	cnt++;
+    }
+
+    poses = (co_aix (*)[2])malloc(sizeof(co_aix [2]) * 2 * cnt);
+    if(poses == NULL)
+	return ERR;
+
+    pos_cnt = 0;
+    for(shape = STAILQ_HEAD(coord->members);
+	shape != NULL;
+	shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) {
+	geo = shape->geo;
+	
+	area_to_positions(&geo->areas[0], poses + pos_cnt);
+	pos_cnt += 2;
+	area_to_positions(&geo->areas[1], poses + pos_cnt);
+	pos_cnt += 2;
+    }
+
+    for(i = 0; i < pos_cnt; i++)
+	coord_trans_pos(coord, &poses[i][0], &poses[i][1]);
+
+    area_init(coord->cur_area, cnt, poses);
+    free(poses);
+
+    return OK;
 }
 
 static void draw_shape(redraw_man_t *rdman, shape_t *shape) {
+    switch(shape->sh_type) {
+    case SHT_PATH:
+	sh_path_draw(shape, rdman->cr);
+	break;
+    }
 }
 
-static void clip_and_show(redraw_man_t *rdman, int n_dirty_areas,
-			  area_t **dirty_areas) {
+static void make_clip(redraw_man_t *rdman, int n_dirty_areas,
+		      area_t **dirty_areas) {
+    int i;
+    area_t *area;
+    cairo_t *cr;
+
+    cr = rdman->cr;
+
+    cairo_reset_clip(cr);
+    for(i = 0; i < n_dirty_areas; i++) {
+	area = dirty_areas[i];
+	cairo_rectangle(cr, area->x, area->y, area->w, area->h);
+    }
+    cairo_clip(cr);
+}
+
+static void draw_shapes_in_areas(redraw_man_t *rdman,
+				 int n_areas,
+				 area_t **areas) {
+    geo_t *visit_geo;
+    int i;
+
+    for(visit_geo = STAILQ_HEAD(rdman->all_geos);
+	visit_geo != NULL;
+	visit_geo = STAILQ_NEXT(geo_t, next, visit_geo)) {
+	if(visit_geo->flags & GEF_DIRTY) {
+	    visit_geo->flags &= ~GEF_DIRTY;
+	    update_shape_geo(visit_geo->shape);
+	}
+	for(i = 0; i < n_areas; i++) {
+	    if(is_overlay(visit_geo->cur_area, areas[i])) {
+		draw_shape(rdman, visit_geo->shape);
+		break;
+	    }
+	}
+    }
 }
 
 /*! \brief Re-draw all changed shapes or shapes affected by changed coords.
@@ -371,14 +454,13 @@
  * - Scan all shapes and redraw shapes overlaid with dirty areas.
  *
  * dirty flag of coord objects is cleared after update.
+ * dirty flag of geo objects is also cleared after recomputing.
+ * Clean dirty flag can prevent redundant computing for geo and
+ * corod objects.
  *
- * assert(n_dirty_geos <= (num_of(shape) + num_of(coord)))
- * Because
- * - num_of(geo from coord) < num_of(coord)
- * - num_of(geo from shape) < num_of(shape)
  */
 int rdman_redraw_changed(redraw_man_t *rdman) {
-    int i;
+    int i, r;
     int n_dirty_coords;
     coord_t **dirty_coords;
     coord_t *visit_coord;
@@ -407,10 +489,11 @@
 		visit_coord->flags &= ~COF_DIRTY;
 
 		SWAP(visit_coord->cur_area, visit_coord->last_area, area_t *);
-		compute_coord_area(visit_coord);
+		r = compute_coord_area(visit_coord);
+		if(r == ERR)
+		    return ERR;
 		add_dirty_area(rdman, visit_coord->cur_area);
 		add_dirty_area(rdman, visit_coord->last_area);
-		make_redrawing_members(rdman, visit_coord);
 	    }
 	}
 	rdman->n_dirty_coords = 0;
@@ -430,21 +513,32 @@
 	    add_dirty_area(rdman, visit_geo->cur_area);
 	    add_dirty_area(rdman, visit_geo->last_area);
 	}
+	rdman->n_dirty_geos = 0;
+    }
 	
-	n_dirty_areas = rdman->n_dirty_areas;
-	dirty_areas = rdman->dirty_areas;
-	for(visit_geo = STAILQ_HEAD(rdman->all_geos);
-	    visit_geo != NULL;
-	    visit_geo = STAILQ_NEXT(geo_t, next, visit_geo)) {
-	    for(i = 0; i < n_dirty_areas; i++) {
-		if(is_overlay(visit_geo->cur_area,
-			      dirty_areas[i])) {
-		    draw_shape(rdman, visit_geo->shape);
-		    break;
-		}
-	    }
+    n_dirty_areas = rdman->n_dirty_areas;
+    dirty_areas = rdman->dirty_areas;
+    if(n_dirty_areas > 0) {
+	make_clip(rdman, n_dirty_areas, dirty_areas);
+	draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas);
+	rdman->n_dirty_areas = 0;
+    }
+
+    return OK;
+}
+
+int rdman_redraw_all(redraw_man_t *rdman) {
+    geo_t *geo;
+
+    /* TODO: update dirty coord and it's members. */
+    for(geo = STAILQ_HEAD(rdman->all_geos);
+	geo != NULL;
+	geo = STAILQ_NEXT(geo_t, next, geo)) {
+	if(geo->flags & GEF_DIRTY) {
+	    geo->flags &= ~GEF_DIRTY;
+	    update_shape_geo(geo->shape);
 	}
-	clip_and_show(rdman, n_dirty_areas, dirty_areas);
+	draw_shape(rdman, geo->shape);
     }
 
     return OK;
@@ -541,7 +635,7 @@
     int n;
     int i;
 
-    redraw_man_init(&rdman);
+    redraw_man_init(&rdman, NULL);
     coords[0] = rdman.root_coord;
     for(i = 1; i < 3; i++) {
 	coords[i] = rdman_coord_new(&rdman, rdman.root_coord);