Hi, I am using GooCanvas for an application that uses clipboard copy. I have found a code that copy the canvas directly to the clipboard (I am sorry, I have lost the original link to the writer of this code...). This code doesn't show the real canvas content. I think that all colors are drawn on a black sheet (the black text coming from the canvas is merged with the black backgound on the clipboard). Let me show you your example. First (a screenshot of widgets-demo.jpg). And the modified example. When I copy the image to the clipboard, I have the following (widgets-demo-clipboard.jpg). The code is the following : guchar convert_color_channel(guchar src, guchar alpha) { return alpha ? ((src << 8) - src) / alpha : 0; } GdkPixbuf * cairo_convert_to_pixbuf (cairo_surface_t *surface) { GdkPixbuf *pixbuf; int width, height; int srcstride, dststride; guchar *srcpixels, *dstpixels; guchar *srcpixel, *dstpixel; int n_channels; int x, y; switch (cairo_image_surface_get_format (surface)) { case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: break; default: g_critical ("This Cairo surface format not supported"); return NULL; break; } width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); srcstride = cairo_image_surface_get_stride (surface); srcpixels = cairo_image_surface_get_data (surface); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); dststride = gdk_pixbuf_get_rowstride (pixbuf); dstpixels = gdk_pixbuf_get_pixels (pixbuf); n_channels = gdk_pixbuf_get_n_channels (pixbuf); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { srcpixel = srcpixels + y * srcstride + x * 4; dstpixel = dstpixels + y * dststride + x * n_channels; dstpixel[0] = convert_color_channel (srcpixel[2], srcpixel[3]); dstpixel[1] = convert_color_channel (srcpixel[1], srcpixel[3]); dstpixel[2] = convert_color_channel (srcpixel[0], srcpixel[3]); dstpixel[3] = srcpixel[3]; } } return pixbuf; } static void on_clipboard_copy(GtkWidget * widget, gpointer p) { cairo_surface_t *surface; cairo_t *cr; GtkClipboard * pClipboard; GdkPixbuf * pPixbuf; gdouble left, top, right, bottom; pClipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); goo_canvas_get_bounds(GOO_CANVAS (canvas), &left, &top, &right, &bottom); surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)right, (int)bottom); cr = cairo_create(surface); cairo_rectangle(cr, left, top, (int)right, (int)bottom); #if 0 cairo_set_source_rgb(cr, 255.0, 255.0, 255.0); #endif cairo_fill(cr); goo_canvas_render((GooCanvas *)canvas, cr, NULL, 1.0); cairo_show_page(cr); pPixbuf = cairo_convert_to_pixbuf(surface); cairo_surface_destroy(surface); cairo_destroy(cr); gtk_clipboard_set_image(pClipboard, pPixbuf); gdk_pixbuf_unref(pPixbuf); } This code is called by a button created in main() like this : w = gtk_button_new_with_label ("Copy To Clipboard"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (on_clipboard_copy), NULL); I know that the goal of GooCanvas is not to take a copy to the clipboard but can you give me some pointers to correctly copy the canvas to the clipboard ? I have tried to fill in white the original cairo surface (see #if 0 in the code) without result... I have join a modified version of the widgets-demo.c code to let you see what is the result. Thank you in advance for any help, Cyril
Attachment:
widgets-demo.jpg
Description: JPEG image
Attachment:
widgets-demo-clipboard.jpg
Description: JPEG image
#include <stdlib.h> #include <goocanvas.h> GtkWidget *canvas; GooCanvasItem *move_item; int num_added_widgets = 0; GList *added_widget_items; static void add_widget_clicked (GtkWidget *button, gpointer data) { GooCanvasItem *root, *witem; GtkWidget *widget; if (num_added_widgets % 2) widget = gtk_label_new ("Hello World"); else widget = gtk_entry_new (); root = goo_canvas_get_root_item (GOO_CANVAS (canvas)); witem = goo_canvas_widget_new (root, widget, num_added_widgets * 50, num_added_widgets * 50, 200, 50, NULL); added_widget_items = g_list_prepend (added_widget_items, witem); num_added_widgets++; } static void remove_widget_clicked (GtkWidget *button, gpointer data) { GooCanvasItem *witem; if (!added_widget_items) return; witem = added_widget_items->data; goo_canvas_item_remove (witem); added_widget_items = g_list_delete_link (added_widget_items, added_widget_items); num_added_widgets--; } static void move_widget_clicked (GtkWidget *button, gpointer data) { static gint move_index = 0; static gdouble moves[][4] = { { 50, 50, -1, -1 }, { 300, 100, -1, -1 }, { 200, 200, -1, -1 }, { 400, 100, -1, -1 }, }; g_object_set (move_item, "x", moves[move_index][0], "y", moves[move_index][1], "width", moves[move_index][2], "height", moves[move_index][3], NULL); move_index = (move_index + 1) % 4; } static void change_anchor_clicked (GtkWidget *button, gpointer data) { static GtkAnchorType anchor = GTK_ANCHOR_CENTER; g_print ("Setting anchor to: %i\n", anchor); g_object_set (move_item, "anchor", anchor, NULL); anchor++; if (anchor > GTK_ANCHOR_EAST) anchor = GTK_ANCHOR_CENTER; } static void change_widget_clicked (GtkWidget *button, gpointer data) { GooCanvasItem *witem; GtkWidget *old_widget, *widget; if (!added_widget_items) return; witem = added_widget_items->data; g_object_get (witem, "widget", &old_widget, NULL); if (GTK_IS_ENTRY (old_widget)) widget = gtk_label_new ("Hello World"); else widget = gtk_entry_new (); g_object_set (witem, "widget", widget, NULL); } static void hide_item_clicked (GtkWidget *button, gpointer data) { g_object_set (move_item, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL); } static void show_item_clicked (GtkWidget *button, gpointer data) { g_object_set (move_item, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL); } static void hide_canvas_clicked (GtkWidget *button, gpointer data) { gtk_widget_hide (canvas); } static void show_canvas_clicked (GtkWidget *button, gpointer data) { gtk_widget_show (canvas); } static void change_transform_clicked (GtkWidget *button, gpointer data) { goo_canvas_item_translate (move_item, 25.0, 25.0); } static gboolean on_delete_event (GtkWidget *window, GdkEvent *event, gpointer unused_data) { gtk_main_quit (); return FALSE; } static gboolean on_focus_in (GooCanvasItem *item, GooCanvasItem *target, GdkEventFocus *event, gpointer data) { gchar *id; id = g_object_get_data (G_OBJECT (item), "id"); g_print ("%s received focus-in event\n", id ? id : "unknown"); /* Note that this is only for testing. Setting item properties to indicate focus isn't a good idea for real apps, as there may be multiple views. */ g_object_set (item, "stroke-color", "black", NULL); return FALSE; } static gboolean on_focus_out (GooCanvasItem *item, GooCanvasItem *target, GdkEventFocus *event, gpointer data) { gchar *id; id = g_object_get_data (G_OBJECT (item), "id"); g_print ("%s received focus-out event\n", id ? id : "unknown"); /* Note that this is only for testing. Setting item properties to indicate focus isn't a good idea for real apps, as there may be multiple views. */ g_object_set (item, "stroke-pattern", NULL, NULL); return FALSE; } static gboolean on_button_press (GooCanvasItem *item, GooCanvasItem *target, GdkEventButton *event, gpointer data) { GooCanvas *canvas; gchar *id; id = g_object_get_data (G_OBJECT (item), "id"); g_print ("%s received button-press event\n", id ? id : "unknown"); canvas = goo_canvas_item_get_canvas (item); goo_canvas_grab_focus (canvas, item); return TRUE; } static gboolean on_key_press (GooCanvasItem *item, GooCanvasItem *target, GdkEventKey *event, gpointer data) { gchar *id; id = g_object_get_data (G_OBJECT (item), "id"); g_print ("%s received key-press event\n", id ? id : "unknown"); return FALSE; } static void create_focus_box (GtkWidget *canvas, gdouble x, gdouble y, gdouble width, gdouble height, gchar *color) { GooCanvasItem *root, *item; root = goo_canvas_get_root_item (GOO_CANVAS (canvas)); item = goo_canvas_rect_new (root, x, y, width, height, "stroke-pattern", NULL, "fill-color", color, "line-width", 5.0, "can-focus", TRUE, NULL); g_object_set_data (G_OBJECT (item), "id", color); g_signal_connect (item, "focus_in_event", G_CALLBACK (on_focus_in), NULL); g_signal_connect (item, "focus_out_event", G_CALLBACK (on_focus_out), NULL); g_signal_connect (item, "button_press_event", G_CALLBACK (on_button_press), NULL); g_signal_connect (item, "key_press_event", G_CALLBACK (on_key_press), NULL); } guchar convert_color_channel(guchar src, guchar alpha) { return alpha ? ((src << 8) - src) / alpha : 0; } GdkPixbuf * cairo_convert_to_pixbuf (cairo_surface_t *surface) { GdkPixbuf *pixbuf; int width, height; int srcstride, dststride; guchar *srcpixels, *dstpixels; guchar *srcpixel, *dstpixel; int n_channels; int x, y; switch (cairo_image_surface_get_format (surface)) { case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: break; default: g_critical ("This Cairo surface format not supported"); return NULL; break; } width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); srcstride = cairo_image_surface_get_stride (surface); srcpixels = cairo_image_surface_get_data (surface); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); dststride = gdk_pixbuf_get_rowstride (pixbuf); dstpixels = gdk_pixbuf_get_pixels (pixbuf); n_channels = gdk_pixbuf_get_n_channels (pixbuf); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { srcpixel = srcpixels + y * srcstride + x * 4; dstpixel = dstpixels + y * dststride + x * n_channels; dstpixel[0] = convert_color_channel (srcpixel[2], srcpixel[3]); dstpixel[1] = convert_color_channel (srcpixel[1], srcpixel[3]); dstpixel[2] = convert_color_channel (srcpixel[0], srcpixel[3]); dstpixel[3] = srcpixel[3]; } } return pixbuf; } static void on_clipboard_copy(GtkWidget * widget, gpointer p) { cairo_surface_t *surface; cairo_t *cr; GtkClipboard * pClipboard; GdkPixbuf * pPixbuf; gdouble left, top, right, bottom; pClipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); goo_canvas_get_bounds(GOO_CANVAS (canvas), &left, &top, &right, &bottom); surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)right, (int)bottom); cr = cairo_create(surface); cairo_rectangle(cr, left, top, (int)right, (int)bottom); #if 0 cairo_set_source_rgb(cr, 255.0, 255.0, 255.0); #endif cairo_fill(cr); goo_canvas_render((GooCanvas *)canvas, cr, NULL, 1.0); cairo_show_page(cr); pPixbuf = cairo_convert_to_pixbuf(surface); cairo_surface_destroy(surface); cairo_destroy(cr); gtk_clipboard_set_image(pClipboard, pPixbuf); gdk_pixbuf_unref(pPixbuf); } int main (int argc, char *argv[]) { GtkWidget *window, *vbox, *hbox, *w, *scrolled_win; GtkWidget *label, *entry, *textview; GtkTextBuffer *buffer; GooCanvasItem *root, *witem; /* Initialize GTK+. */ gtk_set_locale (); gtk_init (&argc, &argv); /* Create the window and widgets. */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (window), 640, 600); gtk_widget_show (window); g_signal_connect (window, "delete_event", G_CALLBACK (on_delete_event), NULL); vbox = gtk_vbox_new (FALSE, 4); gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (window), vbox); hbox = gtk_hbox_new (FALSE, 4); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); w = gtk_button_new_with_label ("Add Widget"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (add_widget_clicked), NULL); w = gtk_button_new_with_label ("Remove Widget"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (remove_widget_clicked), NULL); w = gtk_button_new_with_label ("Move Widget"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (move_widget_clicked), NULL); w = gtk_button_new_with_label ("Change Anchor"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (change_anchor_clicked), NULL); w = gtk_button_new_with_label ("Change Widget"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (change_widget_clicked), NULL); hbox = gtk_hbox_new (FALSE, 4); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); w = gtk_button_new_with_label ("Hide Canvas"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (hide_canvas_clicked), NULL); w = gtk_button_new_with_label ("Show Canvas"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (show_canvas_clicked), NULL); w = gtk_button_new_with_label ("Hide Item"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (hide_item_clicked), NULL); w = gtk_button_new_with_label ("Show Item"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (show_item_clicked), NULL); w = gtk_button_new_with_label ("Change Transform"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (change_transform_clicked), NULL); w = gtk_button_new_with_label ("Copy To Clipboard"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); g_signal_connect (w, "clicked", G_CALLBACK (on_clipboard_copy), NULL); scrolled_win = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN); gtk_widget_show (scrolled_win); gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0); canvas = goo_canvas_new (); GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS); gtk_widget_set_size_request (canvas, 600, 450); goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000); gtk_container_add (GTK_CONTAINER (scrolled_win), canvas); root = goo_canvas_get_root_item (GOO_CANVAS (canvas)); /* Add a few simple items. */ label = gtk_label_new ("Hello World"); witem = goo_canvas_widget_new (root, label, 50, 50, 200, 100, NULL); g_object_set_data (G_OBJECT (witem), "id", "hello"); entry = gtk_entry_new (); move_item = goo_canvas_widget_new (root, entry, 50, 250, 200, 50, NULL); g_object_set_data (G_OBJECT (move_item), "id", "entry1"); entry = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (entry), "Size: -1 x -1"); witem = goo_canvas_widget_new (root, entry, 50, 300, -1, -1, NULL); g_object_set_data (G_OBJECT (witem), "id", "entry2"); entry = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (entry), "Size: 100 x -1"); witem = goo_canvas_widget_new (root, entry, 50, 350, 100, -1, NULL); g_object_set_data (G_OBJECT (witem), "id", "entry3"); /* Use a textview so we can see the width & height of the widget. */ scrolled_win = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), GTK_POLICY_NEVER, GTK_POLICY_NEVER); textview = gtk_text_view_new (); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), "Size: -1 x 100", -1); gtk_widget_show (textview); gtk_container_add (GTK_CONTAINER (scrolled_win), textview); gtk_widget_set_size_request (scrolled_win, 160, 50); witem = goo_canvas_widget_new (root, scrolled_win, 50, 400, -1, 100, NULL); g_object_set_data (G_OBJECT (witem), "id", "scrolledwin"); /* Create a vbox item with several child entry widgets to check focus traversal.*/ vbox = gtk_vbox_new (FALSE, 4); entry = gtk_entry_new (); gtk_widget_show (entry); gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new (); gtk_widget_show (entry); gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new (); gtk_widget_show (entry); gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); witem = goo_canvas_widget_new (root, vbox, 50, 600, -1, -1, NULL); g_object_set_data (G_OBJECT (witem), "id", "vbox"); /* Create a few normal canvas items that take keyboard focus. */ create_focus_box (canvas, 110, 80, 50, 30, "red"); create_focus_box (canvas, 300, 160, 50, 30, "orange"); create_focus_box (canvas, 500, 50, 50, 30, "yellow"); gtk_widget_show (canvas); /* Pass control to the GTK+ main event loop. */ gtk_main (); return 0; }