How to draw a line in a GtkDrawingArea using Cairo with Gtk3 - c

Could someone please show me a minimal working example of using C language for Cairo with Gtk3 to draw a single line in a GtkDrawingArea. I've tried to modify testcairo.c in the Gtk3 tests folder but I can't get it to work. Please don't suggest the tutorials at the Cairo site; Zetcode.com or gnome.org which are either not for use with Gtk3 or not minimal working examples.

I got it. The key difference is that for gtk+3 you must draw from within a "draw" signal handler. With gtk+2 it's from within the "expose-event" signal handler. Here's a minimal working example.

Here is a complete working example:
Make sure gtk3-devel is installed (in Fedora #dnf install gtk3-devel)
In Ubuntu: sudo apt install libgtk-3-dev
to compile: gcc draw.c `pkg-config --cflags gtk+-3.0 --libs gtk+-3.0` -o draw
#include <gtk/gtk.h>
gboolean draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
{
guint width, height;
GdkRGBA color;
GtkStyleContext *context;
context = gtk_widget_get_style_context (widget);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
gtk_render_background(context, cr, 0, 0, width, height);
cairo_arc (cr, width/2.0, height/2.0, MIN (width, height) / 2.0, 0, 2 * G_PI);
gtk_style_context_get_color (context, gtk_style_context_get_state (context), &color);
gdk_cairo_set_source_rgba (cr, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_fill (cr);
return FALSE;
}
gint main(int argc,char *argv[])
{
GtkWidget *window, *drawing_area;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
drawing_area = gtk_drawing_area_new();
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_set_size_request (drawing_area, 200, 100);
g_signal_connect (G_OBJECT (drawing_area), "draw", G_CALLBACK (draw_callback), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}

Anyone doing this in 2020. This is the Zetcode example refactored to work with GTK3, and it draws what you want so the lines are not weirdly connected. I've added comments to explain what's happening.
/* To compile: gcc linetest.c -o linetest `pkg-config --cflags --libs gtk+-3.0`
* C program for basic drawing with GTK+ and cairo.
* Working 2020 example if this got you stuck, http://zetcode.com/gfx/cairo/basicdrawing/
* Note: the above command line uses backticks (`), it's right before 1 on your keyboard.
*/
#include <cairo.h>
#include <gtk/gtk.h>
//function prototypes
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data);
static void do_drawing(cairo_t *cr);
static gboolean clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data);
//end of function prototypes
/* Global variables for storing mouse coordinates,
* count is index of arrays, coordx and coordy are x and y coordinates of the mouse
*/
struct {
int count;
double coordx[100];
double coordy[100];
} glob;
/* Function: on_draw_event
*Parameters: GtkWidget, cairo_t, gpointer
*Use: This is the function we attach to the main method when we want to draw. It calls the do_drawing method.
*Example: g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);
*/
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
/* Function: do_drawing
*Parameters: cairo_t
*Use: It sets cairo canvas settings, and draws shapes with a for loop
*Settings: are commented
*Note: printf is used during debugging to find mouse click coordinates :)
*/
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr, 0, 0, 0);//Line colour
cairo_set_line_width(cr, 0.5);//Line width
if (glob.count > 1) {
cairo_move_to(cr, glob.coordx[0], glob.coordy[0]);
//printf("from: x:%f, y:%f\n",glob.coordx[0],glob.coordy[0]);
}
//Connect lines.
for (int i = 1; i < glob.count; ++i) {
cairo_line_to(cr, glob.coordx[i], glob.coordy[i]);
//printf("to: x:%f, y:%f\n",glob.coordx[i],glob.coordy[i]);
}
// Draw the above.
cairo_stroke(cr);
//resets array so shape can be drawn again.
glob.count = 0;
}
/* Function: clicked
*Parameters: GtkWidget, GdkEventButton, gpointer
*Use: Registers mouse clicks, 1 is right, 3 is left on laptop. Clicks may be 1, 2 or 3 on a desktop
*Note: printf is used during debugging to find mouse click coordinates :)
*/
static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
if (event->button == 1) {
// printf("Right Click");
glob.coordx[glob.count] = event->x;
glob.coordy[glob.count++] = event->y;
// int i;
// for (i =0; i <= glob.count-1; i++) {
// printf("%f\n", glob.coordx[i]);
// }
}
if (event->button == 3) {
//printf("left Click");
gtk_widget_queue_draw(widget);
}
return TRUE;
}
//Main method.
int main(int argc, char *argv[])
{
//widget variables, window and drawing area.
GtkWidget *window;
GtkWidget *darea;
//Set global count 0, so array is at beginning whenver program starts.
glob.count = 0;
//Always have this to start GTK.
gtk_init(&argc, &argv);
//Set new window, set new drawing area.
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
//Add the drawing area to the window.
gtk_container_add(GTK_CONTAINER(window), darea);
//You need this to register mouse clicks.
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
//Attaching draw function to the main method.
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
//You can close window when you exit button.
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
//Register if left or right mouse click.
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);
//Set window position, default size, and title.
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_window_set_title(GTK_WINDOW(window), "Lines");
//Show all widgets.
gtk_widget_show_all(window);
//start window
gtk_main();
return 0;
}

// compila con valac --pkg gtk+-3.0 nombre_archivo.gs
uses
Gtk
Cairo
init
Gtk.init (ref args)
var TestCairo = new Ventana ()
TestCairo.show_all ()
Gtk.main ()
class Ventana : Window
area: Gtk.DrawingArea
init
title = "Test Genie + GTK + Cairo"
set_default_size (400, 400)
window_position = WindowPosition.CENTER
destroy.connect(Gtk.main_quit)
// área de dibujo
area: Gtk.DrawingArea = new Gtk.DrawingArea ()
// conecta el área de dibujo al método dibujar
area.draw.connect (dibujar)
// añade el área de dibujo a la ventana
add (area)
def dibujar (context : Context) : bool
context.set_source_rgba (1, 0, 0, 1)
context.set_line_width (2)
context.move_to (200, 100)
context.line_to (200, 300)
context.move_to (100, 200)
context.line_to (300, 200)
context.stroke ()
return true
More examples of Genie + Gtk + Cairo in http://genie.webierta.skn1.com

Related

How to get GTK Cairo to plot multiple times without a triggering event

I'm fairly new to GTK and Cairo, and I need to write code that will allow it to draw my data in a while(1) loop each time gtk_widget_queue_draw is called. Here's my attempt at it:
#include <cairo.h>
#include <gtk/gtk.h>
#include <unistd.h>
int scrH = 892, // Window dimensions.
scrW = 1427,
type = 0; // What kind of lines to draw.
int on_draw_event(GtkWidget *widget,
cairo_t *cr,
gpointer user_data) {
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_paint(cr);
cairo_set_line_width(cr, 0.5);
if (type == 0) {
// Plot a few horizontal lines.
for (int i = 0; i < scrH; i += 10) {
cairo_set_source_rgb(cr, 0.2, 0.99, 0.2);
cairo_move_to(cr, (double) 10, i);
cairo_line_to(cr, (double) (scrW - 10.0), i);
cairo_stroke(cr);
}
} else {
// Plot a few vertical lines.
for (int i = 0; i < scrW; i += 10) {
cairo_set_source_rgb(cr, 0.99, 0.2, 0.99);
cairo_move_to(cr, (double) i, 10.0);
cairo_line_to(cr, (double) i, (scrW - 10.0));
cairo_stroke(cr);
}
}
return 0;
}
void clicked(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data) {
/* This one works, but is useless for my application.
if (event->button == 1) {
type = 0;
gtk_widget_queue_draw(widget);
} else if (event->button == 3) {
gtk_widget_queue_draw(widget);
type = 1;
} //TEST */
/* This one only plots once, not many times. How can I fix it?
while (1) {
if (++type == 2) { type = 0; }
// This was a failed attempt to fix it. It too only plotted a single time.
// gdk_threads_add_idle((GSourceFunc)gtk_widget_queue_draw, (void*) widget);
gtk_widget_queue_draw(widget);
sleep(1);
} //TEST*/
}
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *darea;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), darea);
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), scrW, scrH);
gtk_window_set_title(GTK_WINDOW(window), "Lines");
gtk_widget_show_all(window);
gtk_main();
}
Sorry about the code length. Graphical environments tend to be sesquipedalian!
The code was compiled with:
gcc -g -o fj testGTK.c `pkg-config --cflags gtk+-3.0 --libs gtk+-3.0`
on a Debian Linux machine. Details? OK: uname -a:
Linux Sirius 4.19.0-14-amd64 #1 SMP Debian 4.19.171-2 (2021-01-30) x86_64 GNU/Linux
GTK uses an event loop. When you call gtk_main(), it starts this loop, which handles click events, drawing your window, etc. The idea is that the loop calls your functions whenever an event happens. Your function handles it, then returns control back to the main loop so it can handle more events.
Your while(1) loop never returns control to the main loop, so no more events will ever be handled--including the draw event you queue inside the loop. (gtk_widget_queue_draw() doesn't redraw the widget immediately; it schedules a redraw for the next loop).
To fix this, instead of a while(1) loop with a sleep() call, try using g_timeout_add(). This will call a function every interval milliseconds as part of that main loop.

GTK3+ - How to update graphics based on mouse click?

I am trying to modify the cairo graphics rendering I found in http://zetcode.com/gfx/cairo/basicdrawing/ so that it updates the graphics when I click the drawing area with the left mouse button. Currently the code in the website uses the right mouse button click to update the graphics.
I have tried adding gtk_widget_queue_draw(widget); to gboolean clicked(), when event->button == 1:
#include <cairo.h>
#include <gtk/gtk.h>
static void do_drawing(cairo_t *);
struct {
int count;
double coordx[100];
double coordy[100];
} glob;
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width(cr, 0.5);
int i, j;
for (i = 0; i <= glob.count - 1; i++ ) {
for (j = 0; j <= glob.count - 1; j++ ) {
cairo_move_to(cr, glob.coordx[i], glob.coordy[i]);
cairo_line_to(cr, glob.coordx[j], glob.coordy[j]);
}
}
glob.count = 0;
cairo_stroke(cr);
}
static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
if (event->button == 1) {
glob.coordx[glob.count] = event->x;
glob.coordy[glob.count++] = event->y;
gtk_widget_queue_draw(widget);
}
if (event->button == 3) {
gtk_widget_queue_draw(widget);
}
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
glob.count = 0;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), darea);
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_window_set_title(GTK_WINDOW(window), "Lines");
gtk_widget_show_all(window);
gtk_main();
return 0;
}
However, this does not work since now the graphics aren't updated at all.
Is there a way of updating the graphics by pressing the left mouse button (button 1) and simultaneously carry out inserting the coordinates to struct glob as before?
Thanks!
You are setting glob.count = 0 after drawing the lines, however glob.count is only updated by one in the clicked() callback, so it will never draw more than a single line. Also the first line is from point (glob.coordx[0], glob.coordy[0]) to (glob.coordx[0], glob.coordy[0]) (that is: it starts and ends at the same point) so it has no length, and will not be visible.
Solution: remove the line glob.count = 0; from do_drawing().
g_signal_connect(window, "button-press-event", G_CALLBACK(clicked), NULL);
When your callback is called, the window (which emits "button-press-event") is passed as first parameter. The queue_draw call queues redraw of window. However, redraw of DrawingArea is not requested and will not happen.
You can:
Queue redraw of DrawingArea
Connect to "button-press-event" of DrawingArea
Without any changes of code: press a mouse button and resize the window. Gtk will see, that DrawingArea has changed (it's resized too) and queue redraw of this widget.

Where is the cairo context object cr declared?

Where, in the following zetcode, is the cairo context cr declared?
#include <cairo.h>
#include <gtk/gtk.h>
static void do_drawing(cairo_t *);
struct {
int count;
double coordx[100];
double coordy[100];
} glob;
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width(cr, 0.5);
int i, j;
for (i = 0; i <= glob.count - 1; i++ ) {
for (j = 0; j <= glob.count - 1; j++ ) {
cairo_move_to(cr, glob.coordx[i], glob.coordy[i]);
cairo_line_to(cr, glob.coordx[j], glob.coordy[j]);
}
}
glob.count = 0;
cairo_stroke(cr);
}
static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
if (event->button == 1) {
glob.coordx[glob.count] = event->x;
glob.coordy[glob.count++] = event->y;
}
if (event->button == 3) {
gtk_widget_queue_draw(widget);
}
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
glob.count = 0;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), darea);
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_window_set_title(GTK_WINDOW(window), "Lines");
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Is cairo context cr automatically declared in the code and associated with the darea (unfortunate name for drawing area) when we call the function
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
?
The widget will emit the signal and pass it's internal cairo context. When you connect a callback to handle the signal, cairo context is sent by the widget, you receive it and work on it.
Draw signal belongs to Gtk Widget class:
gboolean user_function (GtkWidget *widget, CairoContext *cr, gpointer user_data)
From the draw documentation:
This signal is emitted when a widget is supposed to render itself. The
widget 's top left corner must be painted at the origin of the passed
in context and be sized to the values returned by
gtk_widget_get_allocated_width() and
gtk_widget_get_allocated_height().
Signal handlers connected to this signal can modify the cairo context
passed as cr in any way they like and don't need to restore it. The
signal emission takes care of calling cairo_save() before and
cairo_restore() after invoking the handler.
The signal handler will get a cr with a clip region already set to the
widget's dirty region, i.e. to the area that needs repainting.
Complicated widgets that want to avoid redrawing themselves completely
can get the full extents of the clip region with
gdk_cairo_get_clip_rectangle(), or they can get a finer-grained
representation of the dirty region with
cairo_copy_clip_rectangle_list().
I also hated the CairoContext *cr is
not defined but is simply cairo_t *cr

How to rotate image using GTK+ / Cairo

I've got a simple application that is supposed to rotate a decorated wheel so many degrees every x number of milliseconds using GTK+ and Cairo. I've got some code below that calls cairo_rotate() from a timer. However, the image doesn't change. Do I have to invalidate the image to cause the expose-event to fire? I'm so new to Cairo that a simple example demonstrating how to rotate an image using Cairo in GTK+ would be highly appreciated.
#include <cairo.h>
#include <gtk/gtk.h>
cairo_surface_t *image;
cairo_t *cr;
gboolean rotate_cb( void )
{
cairo_rotate (cr, 1);
//cairo_paint(cr);
printf("rotating\n");
return( TRUE );
}
static gboolean
on_expose_event(GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
cr = gdk_cairo_create (widget->window);
cairo_set_source_surface(cr, image, 0, 0);
cairo_paint(cr);
printf("Paint\n");
//cairo_destroy(cr);
return FALSE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
image = cairo_image_surface_create_from_png("wheel.png");
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "expose-event",
G_CALLBACK (on_expose_event), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
g_timeout_add(500, (GSourceFunc) rotate_cb, NULL);
gtk_main();
cairo_destroy(cr);
cairo_surface_destroy(image);
return 0;
}
You need to store the rotation in a variable and put the cairo_rotate(cr, rotation_amt); call into the on_expose_event method, before paint.
Also translate to the center of the window, rotate, and translate back, to make the wheel rotate around it's center, if the image is centered.
cairo_translate(cr, width / 2.0, height / 2.0);
cairo_rotate(cr, rotation_amt);
cairo_translate(cr, - image_w / 2.0, - image_h / 2.0);
cairo_set_source_surface(cr, image, 0, 0);
cairo_paint(cr);
I hope that's right.
And as ptomato said, you need to invalidate your drawing surface by calling gtk_widget_queue_draw from rotate_cb. And keeping a global variable for the Cairo context is redundant. The image doesn't rotate because a newly created context is loaded with an identity matrix and all your previous transformations are reset.
With the help of the cairo mailing list, this is a working example. I'm sharing this for those who might find this useful.
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
#include <stdlib.h>
cairo_surface_t *image;
cairo_t *cr;
gdouble rotation = 0;
GtkWidget *window;
gint image_w, image_h;
double DegreesToRadians( int degrees );
double DegreesToRadians( int degrees )
{
return((double)((double)degrees * ( M_PI/180 )));
}
gboolean rotate_cb( void *degrees )
{
// Any rotation applied to cr here will be lost, as we create
// a new cairo context on every expose event
//cairo_rotate (cr, 4);
rotation += DegreesToRadians((*(int*)(degrees)));
//cairo_paint(cr);
// printf("rotating\n");
// Tell our window that it should repaint itself (ie. emit an expose event)
gtk_widget_queue_draw(window);
return( TRUE );
}
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event,gpointer data)
{
// Make sure our window wasn't destroyed yet
// (to silence a warning)
g_return_if_fail(GTK_IS_WIDGET(widget));
cr = gdk_cairo_create (widget->window);
// We need to apply transformation before setting the source surface
// We translate (0, 0) to the center of the screen,
// so we can rotate the image around its center point,
// not its upper left corner
cairo_translate(cr, image_w/2, image_h/2);
cairo_rotate(cr, rotation);
cairo_set_source_surface(cr, image, -image_w/2, -image_h/2);
// We need to clip around the image, or cairo will paint garbage data
//cairo_rectangle(cr, -image_w/2, -image_h/2, image_w, image_h);
//cairo_clip(cr);
cairo_paint(cr);
//printf("Paint\n");
cairo_destroy(cr);
return FALSE;
}
int main(int argc, char *argv[])
{
int degrees = 10, speed = 125;
image = cairo_image_surface_create_from_png("wheel.png");
image_w = cairo_image_surface_get_width(image);
image_h = cairo_image_surface_get_height(image);
gtk_init(&argc, &argv);
if( argc == 3 )
{
degrees = atoi(argv[1]);
speed = atoi(argv[2]);
}
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "expose-event",
G_CALLBACK (on_expose_event), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), image_w, image_h);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
g_timeout_add(speed, (GSourceFunc) rotate_cb, (void *)&degrees);
gtk_main();
cairo_surface_destroy(image);
return 0;
}

Draw an image on drawing area

I am trying to draw an image on a drawing area with no luck.I saw a couple of python examples but I was not able to implement them into c ,which I am using (eg draw an image to gtk.DrawingArea?)
I have already created a Pixbuf variable to store the image I want to draw on the drawing area,but there are no functions like gtk_drawing_area_draw_pixbuf or something related to that.Any suggestion is appreciated.
You need to make use of expose-event callback (assuming you are working with Gtk+ 2.0) to draw the pixbuf onto drawing area. There is no gtk_drawing_area_draw_pixbuf instead you have gdk_draw_pixbuf. This has been deprecated in favour of gdk_cairo_set_source_pixbuf from version 2.22 onwards. You can call these function in your expose event callback something on these lines (please use them as reference only):
If your Gtk version is < 2.22
static gboolean
da_expose (GtkWidget *da, GdkEvent *event, gpointer data)
{
(void)event; (void)data;
GdkPixbuf *pix;
GError *err = NULL;
/* Create pixbuf */
pix = gdk_pixbuf_new_from_file("/usr/share/icons/cab_view.png", &err);
if(err)
{
printf("Error : %s\n", err->message);
g_error_free(err);
return FALSE;
}
GdkDrawable *draw = gtk_widget_get_window(da);
/* Draw pixbuf */
gdk_draw_pixbuf(draw, NULL, pix, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
return FALSE;
}
Version 2.22 onwards you will have to make use of cairo something on these lines:
static gboolean
da_expose (GtkWidget *da, GdkEvent *event, gpointer data)
{
(void)event; (void)data;
GdkPixbuf *pix;
GError *err = NULL;
/* Create pixbuf */
pix = gdk_pixbuf_new_from_file("/usr/share/icons/cab_view.png", &err);
if(err)
{
printf("Error : %s\n", err->message);
g_error_free(err);
return FALSE;
}
cairo_t *cr;
cr = gdk_cairo_create (da->window);
gdk_cairo_set_source_pixbuf(cr, pix, 0, 0);
cairo_paint(cr);
cairo_fill (cr);
cairo_destroy (cr);
return FALSE;
}
Of course you would have connected to the callback using g_signal_connect (say g_signal_connect (da, "expose-event", G_CALLBACK (da_expose), NULL);). If you are using Gtk+ 3.0 then you will be making use of draw instead of expose-event. You can always refer to gtk-demo/gtk3-demo application which are available to see the samples along with the code. This should be available in the package repository of your distro or you can always get it from source.
Hope this helps!
PS: This link might provide you with some pointers
Now GTK-version is GTK+3.0.
If you are using GTK+3.0, please use as follows.
// gcc expose.c -o expose `pkg-config gtk+-3.0 --cflags --libs`
#include <gtk/gtk.h>
#include <stdlib.h>
static gboolean
on_window_draw (GtkWidget *da, GdkEvent *event, gpointer data)
{
(void)event; (void)data;
GdkPixbuf *pix;
GError *err = NULL;
/* Create pixbuf */
pix = gdk_pixbuf_new_from_file("/usr/share/icons/cab_view.png", &err);
if(err)
{
printf("Error : %s\n", err->message);
g_error_free(err);
return FALSE;
}
cairo_t *cr;
cr = gdk_cairo_create (gtk_widget_get_window(da));
// cr = gdk_cairo_create (da->window);
gdk_cairo_set_source_pixbuf(cr, pix, 0, 0);
cairo_paint(cr);
// cairo_fill (cr);
cairo_destroy (cr);
// return FALSE;
}
int main ( int argc, char **argv) {
GtkWidget *window;
GtkWidget *canvas;
gtk_init (&argc , &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request (window,
50, 50);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit) , NULL);
canvas = gtk_drawing_area_new ();
gtk_container_add (GTK_CONTAINER (window), canvas);
g_signal_connect (canvas, "draw", (GCallback) on_window_draw, NULL);
gtk_widget_set_app_paintable(canvas, TRUE);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}

Resources