1
votes

Im trying to get a image at random location to rotate. I was looking at another similar post(rotate image). But I couldn't get things to work.

#include <gtk/gtk.h>
#include <cairo.h>

GtkWidget *window;

static void rotate_cb()
{
    gtk_widget_queue_draw(window);

}

static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
    GtkWidget *img = (GtkWidget *)(data);
    gint w = gtk_widget_get_allocated_width (img);
    gint h = gtk_widget_get_allocated_height (img);
    gtk_widget_realize(img);
    cairo_surface_t *surface = gdk_window_create_similar_surface(gtk_widget_get_window (img), CAIRO_CONTENT_COLOR, w, h);
    cairo_t *cr = cairo_create (surface);

    cairo_translate(cr, w/2, h/2);
    cairo_rotate(cr, 2);
    cairo_set_source_surface(cr, surface, -w/2, -h/2);

    cairo_paint(cr);
    cairo_destroy(cr);
    cairo_surface_destroy(surface);
    return FALSE;
}


int main(int argc, char *argv[])
{   
    gtk_init(&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
    gtk_widget_set_app_paintable(window, TRUE);
    GtkWidget *l = gtk_layout_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(window), l);
    GtkWidget *img = gtk_image_new_from_file("example.png");
    gtk_layout_put(GTK_LAYOUT(l), img, 300, 300);

    g_signal_connect(window, "draw", G_CALLBACK (on_expose_event), img);
    g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);

    GtkWidget *button = gtk_button_new_with_label("button");
    g_signal_connect(button, "clicked", G_CALLBACK(rotate_cb), NULL);
    gtk_layout_put(GTK_LAYOUT(l), button, 0, 0);

    gtk_widget_show_all(window);
    gtk_main();
}

The window does received the draw signal, but I didn't know how to connect gtkwidget and cairo_surface_t.

Or maybe there are better ways of doing this(without cairo). I prefer all kinds of ideas! Thank you!

1

1 Answers

0
votes

The GtkWidget draw signal handler prototype should be:

gboolean user_function (GtkWidget *widget, CairoContext *cr, gpointer user_data)

as described in the 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(). Parameters

widget - the object which received the signal

cr - the cairo context to draw to

user_data - user data set when the signal handler was connected.

So your on_expose_event function prototype must change and the cairo context will be provided to you:

static gboolean on_expose_event(GtkWidget *widget, cairo_t *cr, gpointer data)
{
.... // your code must change too
}