GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Sat Dec 20, 2014 9:45 am

All times are UTC




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: cairo drawing from outside the "draw" event function
PostPosted: Tue Jan 03, 2012 12:03 pm 
Offline
Familiar Face

Joined: Tue Jan 03, 2012 11:28 am
Posts: 6
I am having big problems getting cairo to work for a complex application.
The application is being converted from GTK2 to GTK3/cairo. The GTK2
version works fine and the GTK3 version has basically the same design.

The application is architected like this:
1. main program creates a permanent GTK drawing area window
2. "draw" event function paints a GdkPixbuf image to the drawing area using cairo
3. "draw" event function also paints lines, pixels and text over the initial image
4. other functions called from main() also paint lines, pixels and text over the image
.....(these are saved in memory and also written by (3) when a "draw" event happens)

The reason I am doing (4) outside the "draw" event function is for interactive
performance: the user is drawing on the window with the mouse. Putting this
in the "draw" event function would be very complicated and have responsiveness
problems (unless I can figure out how to minimize the window refresh to the
few pixels recently added by the user, which would be messy to code).

(2) and (3) work fine. (4) works sometimes.

(4) shows three different behaviors:
4.1 nothing gets drawn on the window until the "draw" event function runs
4.2 something is drawn immediately, as wanted
4.2 the application crashes with the following error:
..... _cairo_surface_begin_modification: Assertion `! surface->finished' failed.

The "draw" event function gets the cairo context in the conventional manner:
void draw_function(GtkWidget *widget, cairo_T *cr, void *userdata)

I have tried two methods of creating the cairo_context for (4):
4.1 cairo_reference(cr) in (2) to stop the automatic destruction and use this cr for the (4) functions.
4.2 cr = gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(gtkdrawingarea)))
..... do the drawing functions, then cairo_destroy(cr)

I must be violating some rules I cannot figure out. What are these?

Is it allowed to have multiple open cairo contexts for the same target
surface (the GTK drawing area)? If not, is there a recommended method
to do this architecture without a big redesign?

Like I said, this worked fine in GTK2.
I used one GDK graphic context for both (2) and (4).


Top
 Profile  
 
 Post subject: Re: cairo drawing from outside the "draw" event function
PostPosted: Tue Jan 03, 2012 8:29 pm 
Offline
Never Seen the Sunlight

Joined: Thu Mar 24, 2011 2:10 pm
Posts: 328
Location: Sydney, Australia
Hang on are you still using gdk contexts? I thought they were depreciated.

I've always done this within the draw function; having a draw and a redraw function. The drawing area is set up as a custom widget with GObject (there's a tutorial on how to do this) that way I can set up signal functions with the mouse behaviour. You can set up some structures that will include the coords of the lines and text. You can then do a redraw when you get a mouse release signal etc. There should be no need to minimise the window.

I've got an example for a plotting widget (though its still in gtk2 but will be an easy transfer) https://github.com/pchilds/GtkPlot -- the plotlinear one is the only one that is complete yet.


Top
 Profile  
 
 Post subject: Re: cairo drawing from outside the "draw" event function
PostPosted: Wed Jan 04, 2012 1:08 pm 
Offline
Familiar Face

Joined: Tue Jan 03, 2012 11:28 am
Posts: 6
Paul Childs: the GDK context was used in the GTK2 version, not the GTK3/Cairo version. My problem is related to the face that I could, in GTK2, update the target window inside the "expose-event" function or from outside, without a problem. In cairo things are different. I wanted to avoid pushing all updates into the "draw" function because this would cause a difficult redesign as well as responsiveness issues.

I think I have figured out some cairo rules I was missing, through experimentation:
1. You cannot create a cairo context outside of the draw function and use it inside the draw function.
2. Inside the draw function you must use the passed cairo context which is created and destroyed each call.
3. The passed cairo context cannot be preserved (via cairo_reference()) and used outside the draw function.
4. To update the target draw area from outside the draw function, you must create a new cairo context, use it, and destroy it. It cannot be open when a draw event happens and the draw function is called.
5. Therefore you must create/use/destroy a new cairo context for each mouse movement if drawing with the mouse. You must not allow a draw event to happen (e.g. window resize) with an open cairo context. I wonder about the overhead for this but have not tried to measure it.

If I am wrong about any of this and if there are less restrictive rules, I would love to hear about it.


Top
 Profile  
 
 Post subject: Re: cairo drawing from outside the "draw" event function
PostPosted: Thu Jan 05, 2012 5:44 am 
Offline
Never Seen the Sunlight

Joined: Thu Mar 24, 2011 2:10 pm
Posts: 328
Location: Sydney, Australia
You've given me lots of information but I'm still having a hard time getting my head around the whole scope of what you are doing and what exactly the issues are.
I'm guessing the problems you're facing are with cairo rather than GTK3 (cairo was used in more recent versions of GTK2 as well)
I use an expose-event signal to trigger drawing (it creates the cairo context and passes it to the draw function so 1-2. don't seem right) and have a redraw function based on clip regions which don't require use of the cairo context (4).
As to the messy to code comment it shouldn't be too bad. If you're worried about the overhead, you could do something like break up the cursor movements into line segments and only update the rectangle bounded by them (define a cairo_region_t, use gdk_window_invalidate_region and then gdk_window_process_updates). If you're storing what is being drawn then once the mouse is released you're best converting the large data set of line segments into a smaller set.
You might want to look into how something like GIMP does it.


Top
 Profile  
 
 Post subject: Re: cairo drawing from outside the "draw" event function
PostPosted: Fri Jan 06, 2012 11:02 am 
Offline
Familiar Face

Joined: Tue Jan 03, 2012 11:28 am
Posts: 6
Thanks for the help. I am slowly getting around the issues. I am somewhat successful updating the window with each mouse movement, without using gdk_widget_queue_draw() to force a GTK3 "draw" event (equivalent to GTK2 expose-event, which no longer exists) (although some GTK3 docs still refer to this).

After seeing that small cairo geometries draw slowly enough to follow with the eye, I made a simple benchmark and found that cairo is really slow. cairo_rectangle(cr,x,y,1,1) takes over 10 times as long as using a 1-pixel GdkPixbuf source with cairo_paint(), so I am redesigning around this constraint, e.g. I am drawing my own geometries at the pixel level instead of using the cairo functions. A quick google on "gtk cairo slow" shows many complaints. I wish the old GTK2 drawing function would come back and be supported.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group