Le mercredi 23 juillet 2008 à 10:38 +0200, Yann Droneaud a écrit : > Hi, > > I'm trying to write a program to display a picture with full > transparency in its own window (without border), using Composite > extension (ARGB colormap and visual). > Using Cairo correctly (e.g. using operator CAIRO_OPERATOR_SOURCE) fixes my problems, see below. > So here are my little demonstration programs > > - test-gdkpixbuf.c : > > This program does the following: > - looks up the RGBA colormap with gdk_screen_get_rgba_colormap() > - installs the colormap with gtk_widget_set_default_colormap() > - creates a GdkPixbuf with gdk_pixbuf_new_from_file() > - creates a GtkWindow > - sets the widget as GTK_APP_PAINTABLE with > gtk_widget_set_app_paintable() > - disables double buffering with gtk_widget_set_double_buffered() > - in the realize signal handler, it removes any background pixmap > using gdk_window_set_back_pixmap() > - in the expose event handler, it draws the GdkPixBuf using > gdk_draw_pixbuf() > Problem: - gdk_draw_pixbuf() seems to use Cairo with operator CAIRO_OPERATOR_OVER so it composes the GdkPixbuf with the background of the window (or the content of the root window, if it has no background). Two way to fix: Fill the window with a black, full transparency content before calling gdk_draw_pixbuf(): in expose_event(): ... cairo_t *cr = gdk_cairo_create(widget->window); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); cairo_paint(cr); cairo_destroy(cr); gdk_draw_pixbuf(widget->window, ... Or, better, use gdk_cairo_set_source_pixbuf() instead of gdk_draw_pixbuf(): ... cairo_t *cr = gdk_cairo_create(widget->window); gdk_cairo_region(cr, event->region); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); gdk_cairo_set_source_pixbuf(cr, pixbuf, 0.0, 0.0); cairo_paint(cr); cairo_destroy(cr); ... Here, I was using CAIRO_OPERATOR_OVER in my first tests, so the results were the same than with gdk_draw_pixbuf(). My mistake. Fixed program is test-gdkpixbuf-cairo.c > - test-gdkpixbuf-bg.patch: > > Apply the patch on top of test-gdkpixbuf.c to create > test-gdkpixbuf-background.c > This patch set a pixmap as a background, and draw nothing on the > window. Only the realize signal and expose event handlers are > modified: > - realize signal handler creates a new pixmap with gdk_pixmap_new(), > writes the content of the GdkPixBuf with gdk_draw_pixbuf() and then > install the background with gdk_window_set_back_pixmap(). > - expose event handler only call to gdk_window_clear() > Problems: - gdk_create_pixmap() returns a GdkPixmap with undefined content - gdk_draw_pixbuf() composes the GdkPixbuf's content with the undefined content of the GdkPixmap See my post[1] titled "There's something in my pixmap". Same fixes two can be applied here: either initialize the content of the drawable before calling gdk_draw_pixbuf(), either use only cairo to draw the GdkPixbuf with the correct operator: CAIRO_OPERATOR_SOURCE. Remark: I'm still interested in a version using only GDK drawing functions and no Cairo functions. Regards. [1] http://mail.gnome.org/archives/gtk-list/2008-July/msg00107.html -- Yann Droneaud <ydroneaud@xxxxxxxxxxxx>
/* test-gdkpixbuf-cairo.c - draw a RGBA image in a window using Cairo * * Yann Droneaud <ydroneaud@xxxxxxxxxxxx> * */ #include <gtk/gtk.h> #include <gdk/gdk.h> #include <gdk/gdkkeysyms.h> #include <gdk-pixbuf/gdk-pixbuf.h> static void realize_signal(GtkWidget *widget, gpointer data) { gdk_window_set_back_pixmap(widget->window, NULL, FALSE); return; } static void destroy_signal(GtkWidget *widget, gpointer data) { gtk_main_quit(); return; } static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { if (event->button == 1 && (event->state & GDK_CONTROL_MASK)) { gtk_window_begin_move_drag(GTK_WINDOW(widget), (gint) event->button, (gint) event->x_root, (gint) event->y_root, event->time); return TRUE; } return FALSE; } static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { /* handle move if mouse button is pressed and later ctrl is hit */ if ((event->keyval == GDK_Control_L || event->keyval == GDK_Control_R) && (event->state & GDK_BUTTON1_MASK)) { gint x; gint y; gdk_display_get_pointer(gdk_display_get_default(), NULL, /* screen */ &x, &y, NULL); /* state */ gtk_window_begin_move_drag(GTK_WINDOW(widget), (gint) 1, /* first button, see mask */ x, y, event->time); return TRUE; } if (event->keyval == GDK_Escape) { gtk_main_quit(); return TRUE; } return FALSE; /* event not handled */ } static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { GdkPixbuf *pixbuf = (GdkPixbuf *) data; cr = gdk_cairo_create(widget->window); gdk_cairo_region(cr, event->region); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); gdk_cairo_set_source_pixbuf(cr, pixbuf, 0.0, 0.0); cairo_paint(cr); cairo_destroy(cr); return TRUE; } int main(int argc, char *argv[]) { GdkScreen *screen; GtkWidget *window; GdkColormap *colormap; const char *color_name = NULL; GdkColor color; const char *pixbuf_name = NULL; GdkPixbuf *pixbuf; GError *error = NULL; gtk_init (&argc, &argv); if (argc > 1 && argv[1] != NULL && *argv[1] != '\0') { pixbuf_name = argv[1]; } if (argc > 2 && argv[2] != NULL && *argv[2] != '\0') { color_name = argv[2]; } if (pixbuf_name == NULL) { g_printerr("missing parameter\n"); return 1; } /* get RGBA colormap */ screen = gdk_screen_get_default(); colormap = gdk_screen_get_rgba_colormap(screen); if (colormap == NULL) { g_printerr("no RGBA colormap\n"); return 1; } /* use the RGBA colormap */ gtk_widget_set_default_colormap(colormap); /* load the pixbuf */ pixbuf = gdk_pixbuf_new_from_file(argv[1], &error); if (pixbuf == NULL) { g_printerr("can't load pixbuf\n"); return 1; } /* check pixbuf format */ if (gdk_pixbuf_get_has_alpha(pixbuf) != TRUE || gdk_pixbuf_get_n_channels(pixbuf) != 4 || gdk_pixbuf_get_bits_per_sample(pixbuf) != 8) { g_printerr("incorrect pixbuf format !\n"); return 1; } window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_set_double_buffered(window, FALSE); /* unneeded, see gtk_widget_set_default_colormap() */ gtk_widget_set_colormap(window, colormap); gtk_window_set_decorated(GTK_WINDOW(window), FALSE); gtk_window_set_resizable(GTK_WINDOW(window), FALSE); gtk_window_set_title(GTK_WINDOW(window), "simple"); gtk_widget_set_size_request(window, gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); if (color_name != NULL) { gdk_color_parse(color_name, &color); gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); } g_signal_connect_after(G_OBJECT(window), "realize", G_CALLBACK(realize_signal), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy_signal), NULL); g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(key_press_event), NULL); g_signal_connect(G_OBJECT(window), "button_press_event", G_CALLBACK(button_press_event), NULL); g_signal_connect(G_OBJECT(window), "expose_event", G_CALLBACK(expose_event), pixbuf); gtk_widget_add_events(window, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK); gtk_widget_show(window); gtk_main (); return 0; }
_______________________________________________ gtk-list mailing list gtk-list@xxxxxxxxx http://mail.gnome.org/mailman/listinfo/gtk-list