Problems with transparent background

Martin Fischer <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
Hi,

I'm working on an CAD application that needs to be ported to GTK3. For 
that purpose I need to find out the best way to handle dragging drawing 
elements from one position to another.

My idea is to create a surface that has all the static elemants. Another 
surface should have a transparent background and the element that is 
currently moved.

To try out that concept I created a small application:

----
/*
  * gcc raster2.c -o raster2 `pkg-config --cflags --libs gtk+-2.0`
  */

#include <gtk/gtk.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>

struct {
   cairo_surface_t *image;
   cairo_surface_t *ball;
} glob;


double px = 10;
double py = 100;
double vx = 2;
double vy = 2;


/* create a bunch of green lines on white as background */

void CreateBackground(cairo_surface_t *destination )
{
	cairo_t *cr;
	int i;
	
	glob.image = cairo_surface_create_similar_image (destination,
                                     CAIRO_FORMAT_ARGB32,
                                     200,
                                     200);


     cr = cairo_create( glob.image );

     cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
     cairo_paint(cr);

     cairo_set_source_rgba(cr,0,1.0,0, 1.0);

     for( i = 0; i <= 200; i+=10 ) {
		cairo_move_to( cr, i, 0 );
		cairo_line_to( cr, i, 200 );
		cairo_move_to( cr, 0, i );
		cairo_line_to(cr, 200, i );
	}
     cairo_stroke(cr);
	cairo_destroy(cr);
}

/* create a transparent background and a red dot */

void CreateForeground()
{
	cairo_t *cr;

     cr = cairo_create( glob.ball );

     /* why has alpha to be greater than 0.0? */
	cairo_set_source_rgba (cr, 0, 0, 0, 0.01);
	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
	cairo_paint (cr);
	
     cairo_set_source_rgba(cr,1.0,0,0, 1);

     cairo_arc(cr, px, py, 6, 0, 2*M_PI);
     cairo_fill(cr);

     cairo_destroy(cr);

}

/* when called, create a new foreground surface and invalidate old
  * position. Finally calculate the next position */

gboolean timeout(gpointer data)
{
     GtkWidget *widget = GTK_WIDGET(data);
     GdkRectangle rect;
     if (!widget->window) return TRUE;

	CreateForeground();

	rect.x = px - 3;
     rect.y = py - 3;
     rect.width = 6;
     rect.height = 6;		
     gdk_window_invalidate_rect( widget->window, &rect, FALSE );
     gtk_widget_queue_draw(widget);

     if (px <= 3 || px >= 200-3) vx = -vx ;
     if(py <= 3 || py >= 200-3 ) vy = -vy;
     px += vx;
     py += vy;

     return TRUE;
}

/* draw the animation:
  * 1. clip to the changed area
  * 2. draw the background
  * 3. draw the surface containing the red dot on top
  */

gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
     cairo_t *cr = gdk_cairo_create(widget->window);

     if( glob.image == NULL )
		CreateBackground( cairo_get_target (cr));
		
     cairo_rectangle(cr, event->area.x, event->area.y, 
event->area.width, event->area.height);
     cairo_clip(cr);
     cairo_set_source_surface(cr, glob.image, 0, 0);
     cairo_paint(cr);

	cairo_set_operator( cr, CAIRO_OPERATOR_OVER );
	cairo_set_source_surface( cr, glob.ball, 0, 0 );
	cairo_paint(cr);
	
	cairo_destroy( cr );

     return FALSE;
}

int main(int argc, char *argv[])
{
     char *title = "Test";
     int sx = 200;
     int sy = 200;

	gtk_init(NULL,NULL);
		
	glob.ball = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA,
                                 NULL);

     GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     gtk_window_set_title(GTK_WINDOW(window),title);
     gtk_container_set_border_width(GTK_CONTAINER (window), 2);

     g_signal_connect(window, "destroy",G_CALLBACK(gtk_main_quit),&window);
     GtkWidget *drawing_area = gtk_drawing_area_new();

	if( drawing_area ) {
	    GdkScreen *screen = gtk_widget_get_screen(drawing_area);
		GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);

		if( colormap == NULL ) {
			printf("Screen does not support alpha!\n");
		}
	}	

     gtk_widget_set_size_request(drawing_area, sx, sy);

     g_signal_connect(drawing_area,"expose_event",G_CALLBACK(expose),NULL);

     gtk_container_add(GTK_CONTAINER(window), drawing_area);
     gtk_widget_show(drawing_area);

     g_timeout_add(10, timeout, window);

     if (!GTK_WIDGET_VISIBLE (window))
         gtk_widget_show_all(window);
     else {
         gtk_widget_destroy (window);
         window = NULL;
     }

     gtk_main();

     cairo_surface_destroy(glob.image);
	cairo_surface_destroy(glob.ball);
}
----

The expected result is a small window with e few green lines and a red 
circle moving across it.

This mostly works with one exception. The alpha value for the 
transparent background has to be set to a value slightly larger than the 
expected 0.0! (See CreateForeground()). If I set it to 0.0 I get some 
strange flickering but no correct rendering.

What am I doing wrong? Any hints and tips welcome.

Regards,
Martin
-- 
cairo mailing list
[email protected]
https://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.