cairovalaclutter

Why does Cairo.set_source_rgb paint the whole canvas?


I'm playing around with Clutter/cairo and I'm trying to draw a rectangle; however, it appears that the set_source_rgb is automatically painting the whole canvas with its source, regardless of whether or not I tell it to draw a rectangle (that is, even when I remove the ctx.rectangle() and ctx.fill() lines, the rectangle is still drawn). Why is this? And what do I need to do to have the rectangle do the painting rather than the set_source_rgb?

public class AnActor : Clutter.Actor {

    public Clutter.Canvas canvas;

    public AnActor() {
        canvas = new Clutter.Canvas();
        canvas.set_size(300,300);

        this.set_content( canvas );
        this.set_size(300,300);

        //Connect to the draw signal.
        canvas.draw.connect(drawme);
    }

    private bool drawme( Cairo.Context ctx, int w, int h) {
        stdout.printf("Just to test this ran at all: %d\n", w);

        ctx.scale(w,h);
        ctx.set_source_rgb(0,0,0);

        //Why is this rectangle drawn even when I remove these lines?
        ctx.rectangle(0,0,200,200);
        ctx.fill();

        ctx.paint();

        return true;
    }
}



int main(string [] args) {
    // Start clutter.
    var result = Clutter.init(ref args);
    if (result != Clutter.InitError.SUCCESS) {
        stderr.printf("Error: %s\n", result.to_string());
        return 1;
    }

    var stage = Clutter.Stage.get_default();
    stage.destroy.connect(Clutter.main_quit);

    //Make my custom Actor:
    var a = new AnActor();
    stage.add_child(a);
    a.canvas.invalidate();

    stage.show_all();

    Clutter.main();
    return 0;
}

Solution

  • It seems to me that there are actually a couple of misunderstandings in the drawme method:

    ctx.scale(w,h);
    

    Judging by what you do later, it seems like you think this means that you want to scale what you're doing so that you can draw stuff between 0,0 and 300,300. What you're actually doing is going in the other direction... if you keep this line here, you need to draw between 0,0 and 1,1.

    ctx.rectangle(0,0,200,200);
    ctx.fill();
    

    Here you're asking for a rectangle from the origin to 200 * the width and height of your canvas. If you change it to ctx.rectangle (0, 0, 0.67, 0.67) the result should be closer to what you wanted. Or, as I mentioned earlier, you could just get rid of the ctx.scale(w,h); call.

    ctx.paint();
    

    Take a look at the documentation for cairo_paint: "A drawing operator that paints the current source everywhere within the current clip region." What you want is to fill the current path, which is what cairo_fill does. Since you haven't defined a clip region, the entire context gets filled.

    Alternately, you could create a clip region with cairo_clip; just add a ctx.clip (); right before ctx.paint ();. You'll probably want to use cairo_save and cairo_restore--the documentation for cairo_clip explains it.