
{"id":2747,"date":"2010-08-27T01:40:21","date_gmt":"2010-08-26T20:10:21","guid":{"rendered":"http:\/\/www.jeffrin.in\/?p=2747"},"modified":"2010-08-27T01:40:21","modified_gmt":"2010-08-26T20:10:21","slug":"cairo-graphics-1-1-beautification","status":"publish","type":"post","link":"https:\/\/www.trueangle.org\/index.php\/2010\/08\/27\/cairo-graphics-1-1-beautification\/","title":{"rendered":"cairo graphics 1.1 beautification"},"content":{"rendered":"<p><a href=\"http:\/\/www.jeffrin.in\/wp-content\/uploads\/2010\/08\/cairobeautification.png\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.jeffrin.in\/wp-content\/uploads\/2010\/08\/cairobeautification-300x225.png\" alt=\"\" title=\"cairobeautification\" width=\"300\" height=\"225\" class=\"alignnone size-medium wp-image-2749\" \/><\/a><br \/>\n<code><br \/>\n\/* Jeffrin Jose  Licensed GPL v3 Copyright<br \/>\nAugust 2010 GPL --&gt; http:\/\/www.gnu.org\/copyleft\/gpl.html *\/<\/p>\n<p>#include<br \/>\n#include<br \/>\n#include<br \/>\n#include<\/p>\n<p>\/\/the global pixmap that will serve as our buffer<br \/>\nstatic GdkPixmap *pixmap = NULL;<\/p>\n<p>gboolean on_window_configure_event(GtkWidget * da, GdkEventConfigure * event, gpointer user_data){<br \/>\n    static int oldw = 0;<br \/>\n    static int oldh = 0;<br \/>\n    \/\/make our selves a properly sized pixmap if our window has been resized<br \/>\n    if (oldw != event-&gt;width || oldh != event-&gt;height){<br \/>\n        \/\/create our new pixmap with the correct size.<br \/>\n        GdkPixmap *tmppixmap = gdk_pixmap_new(da-&gt;window, event-&gt;width,  event-&gt;height, -1);<br \/>\n        \/\/copy the contents of the old pixmap to the new pixmap.  This keeps ugly uninitialized<br \/>\n        \/\/pixmaps from being painted upon resize<br \/>\n        int minw = oldw, minh = oldh;<br \/>\n        if( event-&gt;width width; }<br \/>\n        if( event-&gt;height height; }<br \/>\n        gdk_draw_drawable(tmppixmap, da-&gt;style-&gt;fg_gc[GTK_WIDGET_STATE(da)], pixmap, 0, 0, 0, 0, minw, minh);<br \/>\n        \/\/we're done with our old pixmap, so we can get rid of it and replace it with our properly-sized one.<br \/>\n        g_object_unref(pixmap);<br \/>\n        pixmap = tmppixmap;<br \/>\n    }<br \/>\n    oldw = event-&gt;width;<br \/>\n    oldh = event-&gt;height;<br \/>\n    return TRUE;<br \/>\n}<\/p>\n<p>gboolean on_window_expose_event(GtkWidget * da, GdkEventExpose * event, gpointer user_data){<br \/>\n    gdk_draw_drawable(da-&gt;window,<br \/>\n        da-&gt;style-&gt;fg_gc[GTK_WIDGET_STATE(da)], pixmap,<br \/>\n        \/\/ Only copy the area that was exposed.<br \/>\n        event-&gt;area.x, event-&gt;area.y,<br \/>\n        event-&gt;area.x, event-&gt;area.y,<br \/>\n        event-&gt;area.width, event-&gt;area.height);<br \/>\n    return TRUE;<br \/>\n}<\/p>\n<p>static int currently_drawing = 0;<br \/>\n\/\/do_draw will be executed in a separate thread whenever we would like to update<br \/>\n\/\/our animation<br \/>\nvoid *do_draw(void *ptr){<\/p>\n<p>    currently_drawing = 1;<\/p>\n<p>    int width, height;<br \/>\n    gdk_threads_enter();<br \/>\n    gdk_drawable_get_size(pixmap, &amp;width, &amp;height);<br \/>\n    gdk_threads_leave();<\/p>\n<p>    \/\/create a gtk-independant surface to draw on<br \/>\n    cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);<br \/>\n    cairo_t *cr = cairo_create(cst);<\/p>\n<p>            \/\/Vertical Line<br \/>\n            cairo_move_to(cr, 200,30);<br \/>\n            cairo_line_to(cr,200,200);<\/p>\n<p>            \/\/Horizontal Line<br \/>\n            cairo_move_to(cr, 120,120);<br \/>\n            cairo_line_to(cr,290,120);<\/p>\n<p>            cairo_rectangle(cr,80,25,300,220);<\/p>\n<p>    \/\/do some time-consuming drawing<br \/>\n    static int i = 0;<br \/>\n    ++i; i = i % 300;   \/\/give a little movement to our animation<br \/>\n    cairo_set_source_rgb (cr, .9, .9, .9);<br \/>\n    cairo_paint(cr);<br \/>\n            cairo_set_source_rgb (cr, 0.8, 0.5, 0.9);<br \/>\n            cairo_move_to(cr, 50,50);<\/p>\n<p>    int j,k;<br \/>\nk=0;<br \/>\n\/*    for(k=0; k&lt;100; ++k){*\/   \/\/lets just redraw lots of times to use a lot of proc power<br \/>\n        for(j=0; j  100)<br \/>\n               {<br \/>\n             cairo_move_to(cr, 200,76);<br \/>\n             cairo_arc(cr, 200+i,76+i,0,0,0);<br \/>\n              }<br \/>\nelse<br \/>\n{<br \/>\n             cairo_arc(cr, 100+i,76,0,0,0);<br \/>\n}<\/p>\n<p>        \/*    cairo_rectangle(cr,50+i,50+i,50,50); *\/<\/p>\n<p>            cairo_stroke(cr);<br \/>\n        }<br \/>\n \/*   }*\/<br \/>\n    cairo_destroy(cr);<\/p>\n<p>    \/\/When dealing with gdkPixmap's, we need to make sure not to<br \/>\n    \/\/access them from outside gtk_main().<br \/>\n    gdk_threads_enter();<\/p>\n<p>    cairo_t *cr_pixmap = gdk_cairo_create(pixmap);<br \/>\n    cairo_set_source_surface (cr_pixmap, cst, 0, 0);<br \/>\n    cairo_paint(cr_pixmap);<br \/>\n    cairo_destroy(cr_pixmap);<\/p>\n<p>    gdk_threads_leave();<\/p>\n<p>    cairo_surface_destroy(cst);<\/p>\n<p>    currently_drawing = 0;<\/p>\n<p>    return NULL;<br \/>\n}<\/p>\n<p>gboolean timer_exe(GtkWidget * window){<\/p>\n<p>    static gboolean first_execution = TRUE;<\/p>\n<p>    \/\/use a safe function to get the value of currently_drawing so<br \/>\n    \/\/we don't run into the usual multithreading issues<br \/>\n    int drawing_status = g_atomic_int_get(&amp;currently_drawing);<\/p>\n<p>    \/\/if we are not currently drawing anything, launch a thread to<br \/>\n    \/\/update our pixmap<br \/>\n    if(drawing_status == 0){<br \/>\n        static pthread_t thread_info;<br \/>\n        int  iret;<br \/>\n        if(first_execution != TRUE){<br \/>\n            pthread_join(thread_info, NULL);<br \/>\n        }<br \/>\n        iret = pthread_create( &amp;thread_info, NULL, do_draw, NULL);<br \/>\n    }<\/p>\n<p>    \/\/tell our window it is time to draw our animation.<br \/>\n    int width, height;<br \/>\n    gdk_drawable_get_size(pixmap, &amp;width, &amp;height);<br \/>\n    gtk_widget_queue_draw_area(window, 0, 0, width, height);<\/p>\n<p>    first_execution = FALSE;<\/p>\n<p>    return TRUE;<\/p>\n<p>}<\/p>\n<p>int main (int argc, char *argv[]){<\/p>\n<p>    \/\/we need to initialize all these functions so that gtk knows<br \/>\n    \/\/to be thread-aware<br \/>\n    if (!g_thread_supported ()){ g_thread_init(NULL); }<br \/>\n    gdk_threads_init();<br \/>\n    gdk_threads_enter();<\/p>\n<p>    gtk_init(&amp;argc, &amp;argv);<\/p>\n<p>    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);<br \/>\n    GdkColor color;<br \/>\n    color.red = 0xffff;<br \/>\n    color.green = 0xffff;<br \/>\n    color.blue = 0;<br \/>\n    gtk_widget_set_size_request (GTK_WIDGET (window), 500, 400);<br \/>\n    gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &amp;color);<br \/>\n    g_signal_connect(G_OBJECT(window), \"destroy\", G_CALLBACK(gtk_main_quit), NULL);<br \/>\n    g_signal_connect(G_OBJECT(window), \"expose_event\", G_CALLBACK(on_window_expose_event), NULL);<br \/>\n    g_signal_connect(G_OBJECT(window), \"configure_event\", G_CALLBACK(on_window_configure_event), NULL);<\/p>\n<p>    \/\/this must be done before we define our pixmap so that it can reference<br \/>\n    \/\/the colour depth and such<br \/>\n    gtk_widget_show_all(window);<\/p>\n<p>    \/\/set up our pixmap so it is ready for drawing<br \/>\n    pixmap = gdk_pixmap_new(window-&gt;window,700,700,-1);<br \/>\n    \/\/because we will be painting our pixmap manually during expose events<br \/>\n    \/\/we can turn off gtk's automatic painting and double buffering routines.<br \/>\n    gtk_widget_set_app_paintable(window, TRUE);<br \/>\n    gtk_widget_set_double_buffered(window, FALSE);<\/p>\n<p>    (void)g_timeout_add(33, (GSourceFunc)timer_exe, window);<\/p>\n<p>    gtk_main();<br \/>\n    gdk_threads_leave();<\/p>\n<p>    return 0;<br \/>\n}<br \/>\n<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\/* Jeffrin Jose Licensed GPL v3 Copyright August 2010 GPL &#8211;&gt; http:\/\/www.gnu.org\/copyleft\/gpl.html *\/ #include #include #include #include \/\/the global pixmap that will serve as our buffer static GdkPixmap *pixmap = NULL; gboolean on_window_configure_event(GtkWidget * da, GdkEventConfigure * event, gpointer user_data){ static int oldw = 0; static int oldh = 0; \/\/make our selves a properly &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.trueangle.org\/index.php\/2010\/08\/27\/cairo-graphics-1-1-beautification\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;cairo graphics 1.1 beautification&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[255,464,517,859,1035],"_links":{"self":[{"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/posts\/2747"}],"collection":[{"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/comments?post=2747"}],"version-history":[{"count":0,"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/posts\/2747\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/media?parent=2747"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/categories?post=2747"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.trueangle.org\/index.php\/wp-json\/wp\/v2\/tags?post=2747"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}