diff --git a/ccc/cc-camera.c b/ccc/cc-camera.c index 94177f2..98454ce 100644 --- a/ccc/cc-camera.c +++ b/ccc/cc-camera.c @@ -162,13 +162,14 @@ camera_set_property(GObject * object, static void camera_render(CcItem * item, CcView * view, - cairo_t* cr) + cairo_t* cr, + GdkRegion * region) { cairo_surface_t* surface; cairo_t * surface_cr; if(CC_ITEM_CLASS(cc_camera_parent_class)->render) { - CC_ITEM_CLASS(cc_camera_parent_class)->render(item, view, cr); + CC_ITEM_CLASS(cc_camera_parent_class)->render(item, view, cr, region); } if(!CC_IS_ITEM(P(item)->root)) { @@ -183,7 +184,7 @@ camera_render(CcItem * item, cairo_rectangle(surface_cr, 0.0, 0.0, 101.0, 101.0); cairo_set_source_rgba(surface_cr, 0.0, 0.0, 0.0, 0.5); cairo_fill(surface_cr); - cc_item_render(P(item)->root, CC_VIEW(item), surface_cr); + cc_item_render(P(item)->root, CC_VIEW(item), surface_cr, region); cairo_restore(surface_cr); cairo_destroy(surface_cr); diff --git a/ccc/cc-circle.c b/ccc/cc-circle.c index 4861a5e..ab5b0d9 100644 --- a/ccc/cc-circle.c +++ b/ccc/cc-circle.c @@ -173,7 +173,7 @@ cc_update_bounds(CcItem* item, CcView const* view, gpointer data) { } static void -cc_path(CcShape* shape, CcView* view, cairo_t* cr) { +cc_path(CcShape* shape, CcView* view, cairo_t* cr, GdkRegion* region) { CcCircle* self = CC_CIRCLE(shape); gdouble x = self->x, y = self->y, diff --git a/ccc/cc-d-rect.c b/ccc/cc-d-rect.c index 71d30dd..3dceb12 100644 --- a/ccc/cc-d-rect.c +++ b/ccc/cc-d-rect.c @@ -77,6 +77,19 @@ cc_d_rect_union(CcDRect one, CcDRect two, CcDRect* merged) { merged->y2 = MAX(one.y2, two.y2); } +gboolean +cc_d_rect_in_region (CcDRect one, GdkRegion *region) { + GdkRectangle rect; + + rect.x = one.x1; + rect.y = one.y1; + rect.width = one.x2 - one.x1; + rect.height = one.y2 - one.y1; + + return (gdk_region_rect_in (region, &rect) != GDK_OVERLAP_RECTANGLE_OUT); +} + + /* GType stuff */ GType cc_d_rect_get_type(void) { diff --git a/ccc/cc-d-rect.h b/ccc/cc-d-rect.h index 392fadd..831056e 100644 --- a/ccc/cc-d-rect.h +++ b/ccc/cc-d-rect.h @@ -24,6 +24,7 @@ #ifndef CC_D_RECT_H #define CC_D_RECT_H +#include #include G_BEGIN_DECLS @@ -47,6 +48,8 @@ gboolean cc_d_rect_intersect(CcDRect one, void cc_d_rect_union (CcDRect one, CcDRect two, CcDRect* merged); +gboolean cc_d_rect_in_region (CcDRect one, + GdkRegion *region); G_END_DECLS diff --git a/ccc/cc-item.c b/ccc/cc-item.c index 0bc33b5..1d71339 100644 --- a/ccc/cc-item.c +++ b/ccc/cc-item.c @@ -597,14 +597,30 @@ cc_item_remove(CcItem* self, CcItem* child) { * the transformation matrix of @view will be used for rendering. */ void -cc_item_render(CcItem* self, CcView* view, cairo_t* cr) { +cc_item_render(CcItem* self, CcView* view, cairo_t* cr, GdkRegion *region) { + g_return_if_fail(CC_IS_ITEM(self)); g_return_if_fail(CC_IS_VIEW(view)); g_return_if_fail(cr); g_return_if_fail(CC_ITEM_GET_CLASS(self)->render); + if (region) { + CcDRect *area; + const CcDRect *bounds; - CC_ITEM_GET_CLASS(self)->render(self, view, cr); + bounds = cc_item_get_all_bounds (self, view); + if (!bounds) + return; + area = cc_d_rect_copy (bounds); + cc_view_world_to_window(CC_VIEW(view), &area->x1, &area->y1); + cc_view_world_to_window(CC_VIEW(view), &area->x2, &area->y2); + if (!cc_d_rect_in_region (*area, region)) { + g_free (area); + return; + } + g_free (area); + } + CC_ITEM_GET_CLASS(self)->render(self, view, cr, region); } /** @@ -996,17 +1012,17 @@ ci_focus(CcItem* self, CcView* view, GtkDirectionType dir) { } static void -ci_render_child(CcItem* child, gpointer view_and_cr[2]) { - cc_item_render(child, CC_VIEW(view_and_cr[0]), view_and_cr[1]); +ci_render_child(CcItem* child, gpointer view_and_cr_and_region[3]) { + cc_item_render(child, CC_VIEW(view_and_cr_and_region[0]), view_and_cr_and_region[1], view_and_cr_and_region[2]); } static void -ci_render(CcItem* self, CcView* view, cairo_t* cr) { - gpointer view_and_cr[2] = { - view, cr +ci_render(CcItem* self, CcView* view, cairo_t* cr, GdkRegion* region) { + gpointer view_and_cr_and_region[3] = { + view, cr, region }; - cc_item_foreach_child (self, G_FUNC (ci_render_child), view_and_cr); + cc_item_foreach_child (self, G_FUNC (ci_render_child), view_and_cr_and_region); } static void diff --git a/ccc/cc-item.h b/ccc/cc-item.h index cba2b95..c858d87 100644 --- a/ccc/cc-item.h +++ b/ccc/cc-item.h @@ -108,7 +108,8 @@ void cc_item_remove (CcItem * self, CcItem * child); void cc_item_render (CcItem * self, CcView * view, - cairo_t * cr); + cairo_t * cr, + GdkRegion * region); void cc_item_set_grid_aligned(CcItem * self, gboolean grid_aligned); void cc_item_update_bounds (CcItem * self, @@ -166,7 +167,8 @@ struct _CcItemClass { CcDRect const * all_bounds); void (*render) (CcItem * self, CcView * view, - cairo_t * cr); + cairo_t * cr, + GdkRegion * region); void (*update_bounds) (CcItem * self, CcView const * view, gpointer user_data); diff --git a/ccc/cc-rectangle.c b/ccc/cc-rectangle.c index 5bddbf0..5d786d5 100644 --- a/ccc/cc-rectangle.c +++ b/ccc/cc-rectangle.c @@ -259,6 +259,17 @@ cr_update_bounds (CcItem * item, #endif if(!bounds || !cc_d_rect_equal(*bounds, drect)) { + + GdkRectangle rect; + GdkRegion *reg; + rect.x = drect.x1; + rect.y = drect.y1; + + rect.width = drect.x2 - drect.x1; + rect.height = drect.y2 - drect.y1; + + reg = gdk_region_rectangle (&rect); + if(bounds) { cc_item_dirty(item, view, *bounds); cc_hash_map_remove(item->bounds, view); @@ -267,11 +278,13 @@ cr_update_bounds (CcItem * item, cc_hash_map_insert(item->bounds, (gpointer)view, cc_d_rect_copy(&drect)); cc_item_dirty(item, view, drect); cc_item_bounds_changed(item, view); + + gdk_region_destroy (reg); } } static void -cr_path(CcShape* shape, CcView* view, cairo_t* cr) { +cr_path(CcShape* shape, CcView* view, cairo_t* cr, GdkRegion *region) { CcRectangle* self = CC_RECTANGLE(shape); gdouble x1 = self->x, x2 = self->x + self->w, diff --git a/ccc/cc-shape.c b/ccc/cc-shape.c index 24d9792..0b3c369 100644 --- a/ccc/cc-shape.c +++ b/ccc/cc-shape.c @@ -280,22 +280,22 @@ cs_set_property(GObject* object, guint prop_id, GValue const* value, GParamSpec* } static void -cs_render(CcItem* item, CcView* view, cairo_t* cr) { +cs_render(CcItem* item, CcView* view, cairo_t* cr, GdkRegion *region) { CcShape* self = CC_SHAPE(item); g_return_if_fail(CC_SHAPE_GET_CLASS(self)->path); cairo_save(cr); - CC_SHAPE_GET_CLASS(self)->render_content(self, view, cr); + CC_SHAPE_GET_CLASS(self)->render_content(self, view, cr, region); - CC_ITEM_CLASS(cc_shape_parent_class)->render(item, view, cr); + CC_ITEM_CLASS(cc_shape_parent_class)->render(item, view, cr, region); - CC_SHAPE_GET_CLASS(self)->render_border (self, view, cr); + CC_SHAPE_GET_CLASS(self)->render_border (self, view, cr, region); cairo_restore(cr); } static void -cs_render_border(CcShape* self, CcView* view, cairo_t* cr) { +cs_render_border(CcShape* self, CcView* view, cairo_t* cr, GdkRegion* region) { if(self->brush_border) { gdouble width = cc_shape_get_width(self, view); gdouble foo = 0.0, bar = 0.0; @@ -303,7 +303,7 @@ cs_render_border(CcShape* self, CcView* view, cairo_t* cr) { cairo_save(cr); cairo_new_path(cr); - CC_SHAPE_GET_CLASS(self)->path(self, view, cr); + CC_SHAPE_GET_CLASS(self)->path(self, view, cr, region); cairo_set_line_width(cr, width); cc_brush_apply(self->brush_border, view, CC_ITEM(self), cr); cairo_stroke(cr); @@ -312,11 +312,11 @@ cs_render_border(CcShape* self, CcView* view, cairo_t* cr) { } static void -cs_render_content(CcShape* self, CcView* view, cairo_t* cr) { +cs_render_content(CcShape* self, CcView* view, cairo_t* cr, GdkRegion* region) { if(self->brush_content) { cairo_save(cr); cairo_new_path(cr); - CC_SHAPE_GET_CLASS(self)->path(self, view, cr); + CC_SHAPE_GET_CLASS(self)->path(self, view, cr, region); cc_brush_apply(self->brush_content, view, CC_ITEM(self), cr); cairo_fill(cr); cairo_restore(cr); diff --git a/ccc/cc-shape.h b/ccc/cc-shape.h index 14dcfdc..2a30db9 100644 --- a/ccc/cc-shape.h +++ b/ccc/cc-shape.h @@ -69,13 +69,16 @@ struct _CcShapeClass { void (*path) (CcShape* self, CcView * view, - cairo_t* cr); + cairo_t* cr, + GdkRegion * region); void (*render_content) (CcShape* self, CcView * view, - cairo_t* cr); + cairo_t* cr, + GdkRegion * region); void (*render_border) (CcShape* self, CcView * view, - cairo_t* cr); + cairo_t* cr, + GdkRegion * region); }; G_END_DECLS diff --git a/ccc/cc-simple-item.c b/ccc/cc-simple-item.c index 9858e18..4d6ad5d 100644 --- a/ccc/cc-simple-item.c +++ b/ccc/cc-simple-item.c @@ -65,12 +65,13 @@ simple_item_distance (CcItem * item, static void simple_item_render (CcItem * item, CcView * view, - cairo_t* cr) + cairo_t* cr, + GdkRegion *region) { g_signal_emit (item, simple_item_signals[SIGNAL_RENDER], 0, view, cr); if (CC_ITEM_CLASS (cc_simple_item_parent_class)->render) { - CC_ITEM_CLASS (cc_simple_item_parent_class)->render (item, view, cr); + CC_ITEM_CLASS (cc_simple_item_parent_class)->render (item, view, cr, region); } } diff --git a/ccc/cc-text.c b/ccc/cc-text.c index ccef538..573c474 100644 --- a/ccc/cc-text.c +++ b/ccc/cc-text.c @@ -376,27 +376,28 @@ ct_dispose (GObject* object) } static void -ct_render(CcItem* item, CcView* view, cairo_t* cr) { +ct_render(CcItem* item, CcView* view, cairo_t* cr, GdkRegion* region) { CcText* self = CC_TEXT(item); - CC_ITEM_CLASS(cc_text_parent_class)->render(item, view, cr); + CC_ITEM_CLASS(cc_text_parent_class)->render(item, view, cr, region); if(self->editable) { - cc_item_render(P(item)->caret, view, cr); + cc_item_render(P(item)->caret, view, cr, region); } } static void ct_path(CcShape* shape, CcView * view, - cairo_t* cr) + cairo_t* cr, + GdkRegion *region) { CcText * self = CC_TEXT(shape); PangoLayout* layout = self->layout; CcDRect * bounds; gdouble x, y; - PangoFontDescription const* desc_old = pango_layout_get_font_description(layout); - PangoFontDescription * backup = pango_font_description_copy(desc_old ? desc_old : pango_context_get_font_description(pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(pango_cairo_font_map_get_default())))); - PangoFontDescription * desc_new = pango_font_description_copy_static(backup); + PangoFontDescription const* desc_old = NULL; + PangoFontDescription * backup = NULL; + PangoFontDescription * desc_new = NULL; gboolean size_absolute = FALSE; gdouble old_size = 0.0, new_size = 0.0; @@ -410,6 +411,11 @@ ct_path(CcShape* shape, cc_view_world_to_window(view, &x, &y); if(!self->size_pixels) { + desc_old = pango_layout_get_font_description(layout); + backup = pango_font_description_copy(desc_old ? + desc_old : + pango_context_get_font_description(pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(pango_cairo_font_map_get_default())))); + desc_new = pango_font_description_copy_static(backup); size_absolute = pango_font_description_get_size_is_absolute(backup); new_size = old_size = pango_font_description_get_size(backup); @@ -438,10 +444,10 @@ ct_path(CcShape* shape, if(!self->size_pixels) { pango_layout_set_font_description(layout, desc_old ? backup : desc_old); + pango_font_description_free(desc_new); + pango_font_description_free(backup); } - pango_font_description_free(desc_new); - pango_font_description_free(backup); } static void diff --git a/ccc/cc-view-cell-renderer.c b/ccc/cc-view-cell-renderer.c index a75b9fd..4d3cc03 100644 --- a/ccc/cc-view-cell-renderer.c +++ b/ccc/cc-view-cell-renderer.c @@ -166,7 +166,7 @@ cvcr_render(GtkCellRenderer * renderer, cairo_matrix_init_translate(&P(renderer)->matrix, cell_area->x - bounds->x1, cell_area->y - bounds->y1); - cc_item_render(P(renderer)->root, CC_VIEW(renderer), cr); + cc_item_render(P(renderer)->root, CC_VIEW(renderer), cr, NULL); } cairo_destroy(cr); } diff --git a/ccc/cc-view-widget.c b/ccc/cc-view-widget.c index 98d3b1b..2a876b3 100644 --- a/ccc/cc-view-widget.c +++ b/ccc/cc-view-widget.c @@ -831,7 +831,7 @@ cvw_expose_event(GtkWidget* widget, GdkEventExpose* ev) { gdk_cairo_region(cr, ev->region); cairo_clip(cr); cairo_save(cr); - cc_item_render(self->root, CC_VIEW(self), cr); + cc_item_render(self->root, CC_VIEW(self), cr, ev->region); cairo_restore(cr); cairo_destroy(cr); } diff --git a/demo/Makefile.am b/demo/Makefile.am index e64fa82..73cd9cf 100644 --- a/demo/Makefile.am +++ b/demo/Makefile.am @@ -4,6 +4,7 @@ noinst_PROGRAMS=ccc-demo ccc_demo_SOURCES=\ animation.c \ camera.c \ + clip.c \ credits.c \ crossing.c \ demo-canvas.c \ diff --git a/demo/main.c b/demo/main.c index 1753040..f77c63d 100644 --- a/demo/main.c +++ b/demo/main.c @@ -46,6 +46,7 @@ main(int argc, char* argv[]) { demo_window_add(DEMO_WINDOW(mainwin), camera_demo()); demo_window_add(DEMO_WINDOW(mainwin), gradient_demo()); demo_window_add(DEMO_WINDOW(mainwin), animation_demo()); + demo_window_add(DEMO_WINDOW(mainwin), clip_demo()); demo_window_add(DEMO_WINDOW(mainwin), layers_demo()); // FIXME: add some code that raises semi-transparent shapes (make the number of shapes configurable) // FIXME: take the code into a prof folder and write some profile-test diff --git a/demo/main.h b/demo/main.h index 99f40e1..1aaa1ee 100644 --- a/demo/main.h +++ b/demo/main.h @@ -30,6 +30,7 @@ DemoPage* animation_demo (void); DemoPage* camera_demo (void); +DemoPage* clip_demo (void); DemoPage* credits (void); DemoPage* crossing (void); DemoPage* fifteen (void);