How to draw two animations simoultaneusly using Cairo?
I am trying to update two drawing_area widgets simultaneously.
This so far I have got:
Code:
// gcc anim.c `pkg-config --cflags --libs gtk+-3.0` -Wall -o anim -lm
#include <gtk/gtk.h>
#include <math.h>
static cairo_surface_t *surface = NULL;
static cairo_surface_t *surface2 = NULL;
static gboolean
on_configure_event(
GtkWidget *widget,
GdkEventConfigure *event,
gpointer data)
{
static int save_w = 0, save_h = 0;
if (save_w == event->width && save_h == event->height)
return TRUE;
save_w = event->width;
save_h = event->height;
if (surface)
cairo_surface_destroy(surface);
surface = gdk_window_create_similar_surface(
gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR,
save_w, save_h);
cairo_t *cr = cairo_create(surface);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
cairo_destroy(cr);
return TRUE;
}
static gboolean
on_draw(
GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
cairo_set_source_surface(cr, surface, 0, 0);
cairo_paint(cr);
return TRUE;
}
static gboolean
on_draw2(
GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
cairo_set_source_surface(cr, surface2, 0, 0);
cairo_paint(cr);
return TRUE;
}
static gboolean stop_timeout = FALSE;
gboolean
on_timeout(
gpointer data)
{
if (stop_timeout) return FALSE;
GtkWidget *widget = GTK_WIDGET(data);
static int ang = 0;
cairo_t *cr = cairo_create(surface);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
int width = gtk_widget_get_allocated_width(widget);
int height = gtk_widget_get_allocated_height(widget);
int x = (int)(width/2.0 * (cos(3.1416/180*ang) + 1));
int y = (int)(height/2.0 * (sin(3.1416/180*ang) + 1));
ang = (ang + 1) % 360;
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_move_to(cr, width/2, height/4);
cairo_line_to(cr, x, y);
cairo_stroke(cr);
cairo_destroy(cr);
gtk_widget_queue_draw(GTK_WIDGET(data));
return TRUE;
}
gboolean
on_timeout2(
gpointer data)
{
if (stop_timeout) return FALSE;
GtkWidget *widget = GTK_WIDGET(data);
static int ang2 = 0;
cairo_t *cr2 = cairo_create(surface2);
cairo_set_source_rgb(cr2, 1, 1, 1);
cairo_paint(cr2);
int width = gtk_widget_get_allocated_width(widget);
int height = gtk_widget_get_allocated_height(widget);
int x = (int)(width/2.0 * (cos(3.1416/180*ang2) + 1));
int y = (int)(height/2.0 * (sin(3.1416/180*ang2) + 1));
ang2 = (ang2 - 1) % 360;
cairo_set_source_rgb(cr2, 0, 0, 0);
cairo_move_to(cr2, width/2, height/4);
cairo_line_to(cr2, x, y);
cairo_stroke(cr2);
cairo_destroy(cr2);
gtk_widget_queue_draw(GTK_WIDGET(data));
return TRUE;
}
static void
on_destroy(
void)
{
if (surface) cairo_surface_destroy(surface);
}
static void
button_clicked(
GtkWidget *button,
gpointer data)
{
gtk_button_set_label(GTK_BUTTON(button),
stop_timeout ? "Stop" : "Start");
stop_timeout = !stop_timeout;
if (!stop_timeout)
g_timeout_add(10, (GSourceFunc)on_timeout, GTK_WINDOW(data));
}
static void
button_clicked2(
GtkWidget *button,
gpointer data)
{
gtk_button_set_label(GTK_BUTTON(button),
stop_timeout ? "Stop" : "Start");
stop_timeout = !stop_timeout;
if (!stop_timeout)
g_timeout_add(10, (GSourceFunc)on_timeout2, GTK_WINDOW(data));
}
static void
on_activate(
GtkApplication *app,
gpointer user_data)
{
GtkWidget *window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Animate");
g_signal_connect(window, "destroy",
G_CALLBACK(on_destroy), NULL);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
gtk_container_add(GTK_CONTAINER(window), box);
GtkWidget *button = gtk_button_new_with_label("Stop");
;
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
GtkWidget *drawing_area = gtk_drawing_area_new();
GtkWidget *drawing_area2 = gtk_drawing_area_new();
gtk_widget_set_size_request(drawing_area, 300, 300);
gtk_widget_set_size_request(drawing_area2, 300, 300);
gtk_box_pack_start(GTK_BOX(box), drawing_area, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(box), drawing_area2, TRUE, TRUE, 0);
g_signal_connect(GTK_BUTTON(button), "clicked",
G_CALLBACK(button_clicked2), drawing_area2);
g_signal_connect(GTK_BUTTON(button), "clicked",
G_CALLBACK(button_clicked), drawing_area);
g_signal_connect(drawing_area, "draw",
G_CALLBACK(on_draw), NULL);
g_signal_connect(drawing_area,"configure-event",
G_CALLBACK(on_configure_event), NULL);
g_signal_connect(drawing_area2, "draw",
G_CALLBACK(on_draw2), NULL);
g_signal_connect(drawing_area2,"configure-event",
G_CALLBACK(on_configure_event), NULL);
g_timeout_add(10, (GSourceFunc)on_timeout, window);
gtk_widget_show_all(window);
}
int
main(
int argc,
char **argv)
{
GtkApplication *app = gtk_application_new("org.gtk.animate",
G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate",
G_CALLBACK(on_activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
This is not working. I want one clock to go forward while the other goes backwards simultaneously.
My idea here was to create two gtk_drawing_area and two cairo surface objects, which should follow parallel drawing function calls at regular intervals.
What am I missing here?