Advertisement
Guest User

Cairo animation example with threading

a guest
Oct 27th, 2016
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.96 KB | None | 0 0
  1. /**
  2.  * A simple animation using cairo and GTK+
  3.  *
  4.  * This program shows high /usr/libexec/Xorg load while running full screen on Linux
  5.  *
  6.  * Compile with:
  7.  *   gcc `pkg-config --cflags --libs gtk+-3.0` -lm -lpthread main.c
  8.  */
  9.  
  10. #include <gtk/gtk.h>
  11. #include <math.h>
  12. #include <pthread.h>
  13.  
  14. #define NUM_POINTS (1000u)
  15. #define PERIOD (100u)
  16.  
  17. /* Local variables */
  18. static pthread_t drawing_thread;
  19. static pthread_mutex_t mutex;
  20. static cairo_surface_t *surface = NULL;
  21. static int surface_width;
  22. static int surface_height;
  23.  
  24. /* Local function prototypes */
  25. static gboolean invalidate_cb(void *);
  26. static gboolean drawing_area_configure_cb(GtkWidget *, GdkEventConfigure *);
  27. static void drawing_area_draw_cb(GtkWidget *, cairo_t *, void *);
  28. static void * thread_draw(void *);
  29.  
  30. int main(int argc, char **argv)
  31. {
  32.     int i;
  33.     gtk_init(&argc, &argv);
  34.    
  35.     GtkWidget *main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  36.     gtk_window_set_title(GTK_WINDOW(main_window), "Drawing example");
  37.     gtk_window_set_default_size(GTK_WINDOW(main_window), 400, 400);
  38.     GtkWidget *drawing_area = gtk_drawing_area_new();
  39.    
  40.     gtk_container_add(GTK_CONTAINER(main_window), drawing_area);
  41.     gtk_widget_show_all(main_window);
  42.  
  43.     /* Create a new thread to update the stored surface */
  44.     pthread_mutex_init(&mutex, NULL);
  45.     pthread_create(&drawing_thread, NULL, thread_draw, NULL);
  46.  
  47.     /* Create a  timer to invalidate our window at 60Hz, and display the stored surface */
  48.     g_timeout_add(1000 / 60, invalidate_cb, drawing_area);
  49.  
  50.     /* Connect our redraw callback */
  51.     g_signal_connect(drawing_area, "draw", G_CALLBACK(drawing_area_draw_cb), NULL);
  52.  
  53.     /* Connect to the configure event to create the surface */
  54.     g_signal_connect(drawing_area, "configure-event", G_CALLBACK(drawing_area_configure_cb), NULL);
  55.  
  56.     /* Connect the destroy signal */
  57.     g_signal_connect(main_window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
  58.    
  59.     gtk_main();
  60. }
  61.  
  62. static gboolean invalidate_cb(void *ptr)
  63. {
  64.     if (GTK_IS_WIDGET(ptr))
  65.     {
  66.         gtk_widget_queue_draw(GTK_WIDGET(ptr));
  67.         return TRUE;
  68.     }  
  69.     return FALSE;
  70. }
  71.  
  72. static gboolean drawing_area_configure_cb(GtkWidget *widget, GdkEventConfigure *event)
  73. {
  74.     if (event -> type == GDK_CONFIGURE)
  75.     {
  76.         pthread_mutex_lock(&mutex);
  77.         if (surface != (cairo_surface_t *)NULL)
  78.         {
  79.             cairo_surface_destroy(surface);
  80.         }
  81.         GtkAllocation allocation;
  82.         gtk_widget_get_allocation(widget, &allocation);
  83.         surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
  84.         surface_width = allocation.width;
  85.         surface_height = allocation.height;
  86.  
  87.         pthread_mutex_unlock(&mutex);
  88.     }
  89. }
  90.  
  91. static inline float sine_to_point(int x, int width, int height)
  92. {
  93.  
  94.     return (height / 2.0) * sin(x * 2 * M_PI / (PERIOD)) + height / 2.0;
  95. }
  96.  
  97. static void drawing_area_draw_cb(GtkWidget *widget, cairo_t *context, void *ptr)
  98. {
  99.     /* Copy the contents of the surface to the current context */
  100.     pthread_mutex_lock(&mutex);
  101.     if (surface != (cairo_surface_t *)NULL)
  102.     {
  103.         cairo_set_source_surface(context, surface, 0, 0);
  104.         cairo_paint(context);
  105.     }
  106.     pthread_mutex_unlock(&mutex);
  107. }
  108.  
  109. static void * thread_draw(void *ptr)
  110. {
  111.     int i;
  112.     int redraw_number = 0;
  113.     while ( 1 )
  114.     {
  115.         usleep(1E6 / 60); /* Sleep for 60 Hz */
  116.    
  117.         if (surface == (cairo_surface_t *)NULL)
  118.         {
  119.             continue;      
  120.         }
  121.  
  122.         pthread_mutex_lock(&mutex);
  123.         cairo_t *context = cairo_create(surface);
  124.  
  125.         /* Draw the background */  
  126.         cairo_set_source_rgb(context, 1, 1, 1);
  127.         cairo_rectangle(context, 0, 0, surface_width, surface_height);
  128.         cairo_fill(context);
  129.  
  130.         /* Draw a moving sine wave */
  131.         cairo_set_source_rgb(context, 0.5, 0.5, 0);
  132.         cairo_move_to(context, 0, sine_to_point(0 + redraw_number, surface_width, surface_height));
  133.         for (i = 1; i < NUM_POINTS; i++)
  134.         {
  135.             cairo_line_to(context,  i, sine_to_point(i + redraw_number, surface_width, surface_height));   
  136.         }  
  137.         cairo_stroke(context);
  138.  
  139.         redraw_number++;
  140.         cairo_destroy(context);
  141.         pthread_mutex_unlock(&mutex);
  142.     }
  143.  
  144.     return NULL;
  145. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement