Sorry, I still don't get it. In my scenario there is initially is no external request of a region that should be drawn. The only source of what should be drawn, including what areas should be exposed, are in the draw() routine. The challenge is to translate a set of drawing routines to a set of invalidation areas.
In any case I solved it as follows:
- Generate a low resolution ARGB32 image surface
- Call the draw() routine (which receives the information whether it is in mask mode)
- Convert all "dirty" pixels into rectangle tiles.
- Invalidate the lits of tiles.
I hope to post the entire code on github in the next few days.
// Call drawing_cb to and use it to generate the rectangle list
DovtkLassoRectangleList *rect_list = NULL;
int scale_factor = 32;
int low_res_width = (selfp->widget->allocation.width+scale_factor-1) / scale_factor;
int low_res_height = (selfp->widget->allocation.height+scale_factor-1) / scale_factor;
int i;
// This should be created in the creation of DovtkLasso
cairo_t *cr = NULL;
cairo_surface_t *surf = NULL;
if (selfp->do_calc_expose_from_cairo) {
surf=cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
low_res_width,
low_res_height);
cr = cairo_create(surf);
cairo_set_source_rgba(cr,0,0,0,0);
cairo_rectangle(cr, 0,0,low_res_height,low_res_width);
cairo_fill(cr);
cairo_set_source_rgba(cr,0,0,0,1);
}
cairo_scale(cr,1.0/scale_factor,1.0/scale_factor);
selfp->drawing_cb(cr, TRUE, &rect_list);
// Turn surf into a list of rectangles
if (selfp->do_calc_expose_from_cairo) {
int row_idx, col_idx;
// Allocate worse case space
rect_list = dovtk_lasso_rectangle_list_new(low_res_width*low_res_height);
guint8 *buf = cairo_image_surface_get_data(surf);
int rect_idx = 0;
int row_stride = cairo_image_surface_get_stride(surf);
for (row_idx=0; row_idx<low_res_height; row_idx++) {
for (col_idx=0; col_idx<low_res_width; col_idx++) {
// Check for "dirty" pixel and turn it into a tile
if (*(buf + row_stride * row_idx + col_idx * 4+3) > 0) {
cairo_rectangle_t *rect = &rect_list->rectangles[rect_idx++];
rect->x = col_idx*scale_factor;
rect->y = row_idx*scale_factor;
rect->width = scale_factor;
rect->height = scale_factor;
}
}
}
rect_list->num_rectangles = rect_idx;
cairo_destroy(cr);
cairo_surface_destroy(surf);
}
// printf("num_rectangles = %d\n", rect_list->num_rectangles);
// Build a list of expose rectangles from the old and the new lists.
// Better done as a linked list.
DovtkLassoRectangleList *expose_rect_list
= dovtk_lasso_rectangle_list_new(selfp->old_rect_list->num_rectangles
+ rect_list->num_rectangles);
int num_old_rects = selfp->old_rect_list->num_rectangles;
for (i=0; i<num_old_rects; i++)
expose_rect_list->rectangles[i] = selfp->old_rect_list->rectangles[i];
for (i=0; i<rect_list->num_rectangles; i++)
expose_rect_list->rectangles[num_old_rects + i] = rect_list->rectangles[i];
// Expose the old and the new list of rectangles!
for (i=0; i<expose_rect_list->num_rectangles; i++) {
// Shortcut
cairo_rectangle_t *lasso_rect = &expose_rect_list->rectangles[i];
GdkRectangle rect;
rect.x = lasso_rect->x;
rect.y = lasso_rect->y;
rect.width = lasso_rect->width;
rect.height = lasso_rect->height;
#if 0
printf("Invalidate region (%d,%d,%d,%d).\n",
rect.x,rect.y,rect.width,rect.height);
#endif
gdk_window_invalidate_rect(selfp->widget->window,
&rect,
TRUE);
}
On Tue, Aug 17, 2010 at 15:42, Paul Davis
<paul linuxaudiosystems com> wrote:
On Tue, Aug 17, 2010 at 4:39 AM, Dov Grobgeld <
dov grobgeld gmail com> wrote:
> Thanks, but this is not what I am looking for.
>
> Here is a description of my flow, which might e.g. be used to draw a rubber
> band box:
based on an IRC exchange about this a couple of days ago, the answer
is two-fold:
1) you assume that cairo_clip() was called with ev->region before
draw() is invokved
2) you call something like cairo_clip_rectangle_lists() to get the
list of rects that need to be redrawn
there have been some suggestions that one should ignore this and just
redraw everything and let cairo clipping deal with it, but i think
this is clearly wrong when the drawing is computationally expensive.
--p