You are not logged in.

#1 2014-04-03 18:53:36

Unia
Member
From: Stockholm, Sweden
Registered: 2010-03-30
Posts: 2,486
Website

Can not seem to clear cairo surface

Hello all,

I'm trying to patch cairo into dwm. So far, it's working good but I have one issue: I can not seem to clear the surface. I have spammed Trilby so much already (he still has two unread emails, or at least hasn't answered yet - which is perfectly fine as he has other things to do as well) and I don't want to be that annoying little bugger, so I come here instead tongue

Let me explain what is happening: before drawing into the buffer surface, I have to clear it or else the new (transparent) bar will be drawn over the last drawn bar. Before drawing anything (in the drawbar function in dwm.c), I call the drw_clear function which looks like this:

void
drw_clear(Drw *drw) {
	if(!drw)
		return;
	cairo_save(drw->ctx);
	cairo_set_operator(drw->ctx, CAIRO_OPERATOR_CLEAR);
	cairo_paint(drw->ctx);
	cairo_restore(drw->ctx);
}

This should clear the buffer surface so I can freshly draw the new bar into it. Only after this, do I draw things with drw_text and drw_square. When I have drawn everything into the buffer, I map it on screen by drawing it into the other cairo context:

void
drw_map(Drw *drw, Window barwin, int x, int y, unsigned int w, unsigned int h) {
	if(!drw)
		return;
	cairo_xlib_surface_set_drawable(drw->bar, barwin, w, h);
	cairo_set_source_surface(drw->foo, drw->buf, x, y);
	cairo_paint(drw->foo);
	XSync(drw->dpy, False); //FIXME needed?
}

As far as I can see, this should work. However, my previous surface is not cleared and after a few redraws, the statusbar is not transparent anymore. Can you see what I am doing wrong? Should you need it, the full code can be found on my Github: https://github.com/Unia/dwm

EDIT: Trilby, if you read this, please disregard my last email. This is the issue I am having.

Last edited by Unia (2014-04-03 19:04:10)


If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres

Offline

#2 2014-04-05 23:00:10

Unia
Member
From: Stockholm, Sweden
Registered: 2010-03-30
Posts: 2,486
Website

Re: Can not seem to clear cairo surface

Anybody? I have been searching for a solution for a few days now but have yet to find something that works.


If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres

Offline

#3 2014-04-05 23:14:52

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,456
Website

Re: Can not seem to clear cairo surface

Well good thing I waited till it was posted here (kidding) - I think I see the issue now:

You clear the cairo surface - but that is really clear.  It is not holding any background image.  It is cleared to transparent, then you draw some on it.  You then paint this onto the window, but the areas that have been left transparent don't get painted (more precisely, the existing window image and the buffer are merged, where the buffer is opaque, it overwrites the window image, where the buffer is transparent, it does nothing to the window image).

You need to paint some background into the buffer - perhaps you don't even need to clear it, you could just paint the background, then draw the foreground, then blit the whole thing onto the window.

In alopex, all my bars are drawn on transparent surfaces first as I don't know where they may get placed until they are drawn to the screen.  So alopex does this:
1) clear the buffer (make it all alpha=0)
2) draw the foreground into the buffer
3) calculate the location of the bar and use this to opaquely paint a background image into a second buffer
4) paint the first buffer into the second
5) paint the second buffer onto the window.

So I actually have a form of "triple buffering" in alopex.  You should not need this, so I may have led you astray - you might not need to clear the buffer to be transparent.  Perhaps just start at step 3 above:

- paint the approrpriate section of the background image into the buffer
- draw the foreground info on the buffer
- paint the buffer on the window.

This is still double buffered as you should not draw the background on the window, then draw the foreground on the window.  This would lead to an ugly 'flashing' at every redraw.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#4 2014-04-06 19:42:24

Unia
Member
From: Stockholm, Sweden
Registered: 2010-03-30
Posts: 2,486
Website

Re: Can not seem to clear cairo surface

If I comment my drw_clear function, I basically do what you say above:

1. In drw_text, I firstly draw the background for the related text (for example, all the tags are drawn individually by iterating over the tag array and calling drw_text on all elements).
2. Then, still in drw_text, I draw the foreground in the same cairo context as I just drawn the background in. (the context holding the image surface; the buffer) This is in the same cycle of the for-loop in drawbar in which I have just drawn the background!
3. When all the backgrounds and related foregrounds are drawn, I call drw_map:

void
drw_map(Drw *drw, Window barwin, int x, int y, unsigned int w, unsigned int h) {
	 if(!drw)
 		return;
 	//cairo_save(drw->xctx);
 	cairo_xlib_surface_set_drawable(drw->xsur, barwin, w, h);
	cairo_set_source_surface(drw->xctx, drw->buf, x, y);
	cairo_paint(drw->xctx);
	//cairo_restore(drw->xctx);
	XSync(drw->dpy, False); //FIXME needed?
}

This is still leading to the overlaying of newly drawn bars on older bars; so I definitely have to clear something. I have also tried clearing the xlib surface, but this just makes the whole bar black. I have tried everything I can think of and everything I can find on Google. I am completely at a loss of what is going on here... EDIT: I do not remember everything I have tried, but most noticable are that I tried XClearWindow on the bar window, I tried clearing the xlib cairo surface and I tried CAIRO_OPERATOR_SOURCE instead of CAIRO_OPERATOR_OVER (the default). Other than that, I have tried various constructs of clearing surfaces, different orders et cetera.

Last edited by Unia (2014-04-06 20:11:10)


If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres

Offline

#5 2014-04-06 21:03:41

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,456
Website

Re: Can not seem to clear cairo surface

Where is the background being drawn to the buffer.  I suspect there is either a problem there, or at the set_drawable stage.  As you cannot create the xlib surface until that point, is there any reason to create the context?  It's possible the extents of the context are not adjusting to the size of the new target surface (though this is all speculation: I never reset target surfaces).


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#6 2014-04-06 21:09:32

Unia
Member
From: Stockholm, Sweden
Registered: 2010-03-30
Posts: 2,486
Website

Re: Can not seem to clear cairo surface

The background is being drawn to the buffer on line 159-161 in drw.c, in the function drw_text.

I do create the xlib surface before that, but I can not point it to the bar window because that is created after the Drw structure which holds all the cairo stuff - changing this would require some substantial changes in the dwm code, plus that I would need to have a Drw struct per monitor so this is not an ideal step to me.

Mind you, if I don't use transparency everything works fine. I really do suspect I have to clear the xlib surface somehow, but as I said it just turns pure black if I do this.

EDIT: Not sure if you are aware of this, but initially I point my xlib surface to the root window. You can see this code in the top of drw.c

Last edited by Unia (2014-04-06 21:20:40)


If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres

Offline

#7 2014-04-06 22:10:07

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,456
Website

Re: Can not seem to clear cairo surface

Unia wrote:

The background is being drawn to the buffer on line 159-161 in drw.c, in the function drw_text.

But there could be two issues there: 1) the rectangle is drawn with 0.1 opacity, so it is almost not drawn at all, and 2) those coordinates are for the text region, right, what about the rest of the window?


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#8 2014-04-06 22:18:10

Unia
Member
From: Stockholm, Sweden
Registered: 2010-03-30
Posts: 2,486
Website

Re: Can not seem to clear cairo surface

Trilby wrote:
Unia wrote:

The background is being drawn to the buffer on line 159-161 in drw.c, in the function drw_text.

But there could be two issues there: 1) the rectangle is drawn with 0.1 opacity, so it is almost not drawn at all, and 2) those coordinates are for the text region, right, what about the rest of the window?

If I draw it with a value bigger than 0.1, it just goes to opague faster. Those coordinates are indeed for the background, the text coordinates are calculated on lines 167 and 168.

I have made some screenshots showing how the bar gets drawn:

first iteration of the for-loop in drawtext:
06-04-2014-2315.png

second iteration:
06-04-2014-2316.png

etc..

I clear the surface before the first iteration and then never again before the whole bar is drawn. These individual parts do not overlap, so that's not it either.

Last edited by Unia (2014-04-06 22:19:15)


If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres

Offline

#9 2014-04-06 22:24:43

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,456
Website

Re: Can not seem to clear cairo surface

Then I'm confused.  Don't you *want* the background drawn opaquely?  If you draw the background with an alpha layer, that would explain why there is bleed through from the previous drawing.

You need a *clean* background (e.g. a background wallpaper image or a solid color) to be drawn fully opaquely, then you can overlay an alpha layer.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#10 2014-04-06 22:35:04

Unia
Member
From: Stockholm, Sweden
Registered: 2010-03-30
Posts: 2,486
Website

Re: Can not seem to clear cairo surface

I want the background of the statusbar to be semi-transparent, with a non-transparent foreground. I'm getting confused now, are you saying I'm going at this all wrong from the start?

EDIT: You aren't talking about the wallpaper now, right? Background and wallpaper is the same thing in Dutch, so...

Last edited by Unia (2014-04-06 22:38:26)


If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres

Offline

#11 2014-04-06 22:49:49

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,456
Website

Re: Can not seem to clear cairo surface

I am using background and wallpaper synonymously.

Painting an semi-transparent surface onto a window will not make that window semi-transparent.  It will only merge what is already in the window with what is in the semitransparent surface.  If you want the *window* transparent, then you will need to use a compositor.  And that has nothing to do with what you paint onto the window.  Alopex's transparency is all "pseudo-transparency" meaning whatever is behind the window is drawn (opaquely) as a background, then the contents are drawn on top of this.  The contents can be drawn with an alpha setting but these are drawn on top of a fully opaque background.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#12 2014-04-07 09:45:56

Unia
Member
From: Stockholm, Sweden
Registered: 2010-03-30
Posts: 2,486
Website

Re: Can not seem to clear cairo surface

Trilby wrote:

Painting an semi-transparent surface onto a window will not make that window semi-transparent. It will only merge what is already in the window with what is in the semitransparent surface.  If you want the *window* transparent, then you will need to use a compositor.  And that has nothing to do with what you paint onto the window.

Found my confusion! I don't know what I was thinking, but what you just said makes an awful lot of sense tongue

Trilby wrote:

Alopex's transparency is all "pseudo-transparency" meaning whatever is behind the window is drawn (opaquely) as a background, then the contents are drawn on top of this.  The contents can be drawn with an alpha setting but these are drawn on top of a fully opaque background.

If I am not mistaken, you get the required part of the wallpaper and set it as the background in get_mons in xlib.c in Alopex?


If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres

Offline

#13 2014-04-07 11:43:59

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,456
Website

Re: Can not seem to clear cairo surface

Yes.

This does have one challenge though I haven't yet overcome: alopex has to set the wallpaper.  While recently someone claimed to be able to do it with XCB, I don't know that there is any way get get the image data from the root window directly.  So alopex takes a png file as an option in it's configuration, scales that image to the root window size(s) and stores that image to also be used as a source surface for background drawing.

If someone uses xsetroot, or feh, or any other tool to set the root window image, it will interfere with this mechanism.  It is quite easy to detect when the root window background has changed, but I can't find a way to get what it was changed to.

For a bit I set the bar windows background to ParentRelative, then just cleared the bar window before drawing.  But this lead to the unbuffered drawing that created a visible 'flash' every time the window was redrawn.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

Board footer

Powered by FluxBB