Hi Roger,

Would this be similar to using a GtkLayout and a GtkDrawingArea? If you add a 
drawing area to a layout you get draw scrolling and the layout can update the 
part of the drawing area shown on the screen even though the drawing might be 
on a larger area.

Eric

 

 

 

-----Original Message-----
From: rbd <r...@soest.hawaii.edu>
To: gtk-app-devel-list <gtk-app-devel-list@gnome.org>
Sent: Fri, Dec 30, 2016 12:24 pm
Subject: Re: deprecated gtk_cairo_create

Hello Sergei,

Unfortunately the use of the gtk3 DrawingArea is a bit obscure and 
difficult to figure out. However, I have been able to make use of it very 
effectively in conjunction with Cairo drawing ops.

For various reasons I have created a GUI toolkit library which lies 
between my app code and gtk3. This library includes an object known as a 
Canvas, which is essentially a toplevel window with scrollbars parenting a 
DrawingArea. The Canvas object includes a private off-screen Cairo drawing 
surface which I create and control completely, and I do all of my 
application drawing onto that surface. Then, I use the gtk3 draw signal 
mechanism to copy whatever recatngular areas I want from my private 
surface onto the DrawingArea. gtk3 passes to my drawing event handler a 
pointer to a Cairo context which addresses the DrawingArea's own Cairo 
surface, so all I need to do in the draw event handler is set a source 
surface on that context (in my case, the source surface is my own private 
Cairo surface), and copy a rectangle. As far as I know there is no safe 
way to access the Cairo surface of a gtk3 DrawingArea other than through 
the Cairo context pointer passed into the drawing event handler.

Following is some incomplete, stripped down code which may help to explain 
the above ideas. I hope this helps!

Roger Davis
Univ. of Hawaii

######### code follows ###########

/* Here are the relevant parts of the Canvas structure */
typedef struct {
         ...
         GtkWidget *drawarea;    /* created by gtk_drawing_area_new() */
         int width, height;      /* size of DrawingArea */
         cairo_surface_t *surface; /* my private Cairo surface */
         ...
} Canvas;

gboolean
canvasdrawevt(GtkWidget *w, cairo_t *cr, gpointer gp)
/*
    This internal routine handles draw signals sent by GTK+3 to a Canvas'
    GtkDrawingArea widget. These signals will typically be generated by
    expose events or by program calls to gtk_widget_queue_draw_area()
    generated from within canvasflushregion(). This routine merely copies
    the rectangle(s) of interest from the off-screen Cairo drawing surface
    of the canvas into the actual GtkDrawingArea widget.
*/
{
         Canvas *c;

         if (gp == (gpointer) 0)
        return FALSE;
         c= (Canvas *) gp;
         if (w != c->drawarea)
      return FALSE;

         /* here I set the source to my private
            surface which I have already drawn */
         cairo_set_source_surface(cr, c->surface, 0, 0);

         /* note that according to various (and occasionally obscure)
            GTK+3 docs, the context cr passed into this routine has
            already been clipped to any exposed rectangle(s) of interest
            (or whatever canvasflush{reg}() has marked for redraw via
            its call to gtk_widget_queue_draw_area()), so the following
   call to copy the whole drawing surface is not as expensive
            as it looks! */
         cairo_rectangle(cr, 0, 0, (double) c->width, (double) c->height);
         cairo_fill(cr);

         return TRUE;
}

/* Here is how the important parts of the Canvas are created ... */

Canvas *
canvascreate(gint width, gint height, ... )
{
         Canvas *c;
         int i;
         GtkWidget *win, *lo, *sw;
         GdkGeometry geom;

       if ((c= (Canvas *) calloc((MemSizeType) 1, sizeof(Canvas))) == (Canvas 
*) 0)
   return (Canvas *) 0;

         ...

         /* create the DrawingArea */
  c->width= width;
         c->height= height;
         if ((c->drawarea= gtk_drawing_area_new()) == (GtkWidget *) 0) {
                 canvasdestroy(c);
                 return (Canvas *) 0;
         }
         gtk_widget_set_size_request(c->drawarea, width, height);
         gtk_widget_set_can_focus(c->drawarea, TRUE);
         ...

         /* attach the drawing event handler */
         g_signal_connect((gpointer) c->drawarea, "draw", 
G_CALLBACK(canvasdrawevt), (gpointer) c);
         ...

         /* create our private Cairo surface on which we will draw
            everything */
         if ((c->surface= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int) 
width, (int) height)) == (cairo_surface_t *) 0) {
                 canvasdestroy(c);
                 return (GITCanvas *) 0;
         }
        ...

         return c;
}

/* Call this routine to copy our private Cairo surface to the DrawingArea
    whenever we want (i.e., after we have done all our drawing into the
    former).  A call to this routine will result in our drawing event
    handler above being called asynchronously at some later time (but
    probably just about immediately). */
void
canvasflushregion(Canvas *c, int x0, int x1, int y0, int y1)
{
         unsigned int w, h;

         /* my real code checks x0/x1/y0/y1 for
            correctness before proceeding! */
         ...

         w= (unsigned int) (x1-x0+1);
         h= (unsigned int) (y1-y0+1);

         /* the following call will result in GTK+3/GDK sending a draw
            signal on the rectangle of interest that will ultimately be
            handled within canvasdrawevt(); see further comments there */
         gtk_widget_queue_draw_area(c->drawarea, px0, py0, w, h);

         return;
}



_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Reply via email to