c++gtkcairogtkmm

How to cut a part of a shape with the help of another painted shape above?


On the screen below I have the image with the painted translucent rectangle and with the painted opaque rectangle. My purpose is to cut the area of the opaque rectangle - delete pixels in the translucent rectangle in order to see the initial image.

enter image description here

cairo_surface_t *surface = cairo_xlib_surface_create(xdisplay, xroot,  DefaultVisual(xdisplay, scr), DisplayWidth(xdisplay, scr), DisplayHeight(xdisplay, scr));
cairo_t *cr = cairo_create(surface);

cairo_surface_write_to_png(
  surface,
  "test.png");

cairo_surface_t *surfaceTmp = cairo_image_surface_create_from_png("./test.png");




if (xevent.type == MotionNotify && isPressed == true)
{
  int tmp_x = xevent.xmotion.x_root;
  int tmp_y = xevent.xmotion.y_root;

  cairo_save(cr);

  cairo_set_source_surface(cr, surfaceTmp, 1, 1);
  cairo_paint(cr);

  cairo_set_source_rgba(cr, 0, 0, 0, 0.2);
  cairo_rectangle(cr, 0, 0, DisplayWidth(xdisplay, scr), DisplayHeight(xdisplay, scr));
  cairo_fill(cr);

  cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
  cairo_rectangle(cr, init_x, init_y, tmp_x - init_x, tmp_y - init_y); // set rectangle
  cairo_fill(cr);

  cairo_restore(cr);
}

Why do I have this black rectangle? I thought that CAIRO_OPERATOR_CLEAR should delete the shape part beneath.

The desired outcome:

enter image description here


Solution

  • Maybe, since cairo's drawings change pixels directly (=not buffered), once you draw something, there remain no underlying original pixels that can be recovered afterwards. If you'd like to hole the rectangle, try the fill rule: CAIRO_FILL_RULE_EVEN_ODD.

    cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);  // The default is CAIRO_FILL_RULE_WINDING.
    
    cairo_set_source_rgba(cr, 0, 0, 0, 0.2);
    cairo_rectangle(cr, 0, 0, DisplayWidth(xdisplay, scr), DisplayHeight(xdisplay, scr));
    //cairo_fill(cr);
    
    //cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
    cairo_rectangle(cr, init_x, init_y, tmp_x - init_x, tmp_y - init_y); // set rectangle
    
    cairo_fill(cr);