When implementing EVT_PAINT handlers in c++ the PaintDC object is constructed at the beginning of the function, and auto destructed at it''s end, which informs wxwidgets that "invalid regions in the window have been repainted". Under ruby, this is not the case and causes a stream of EVT_PAINT events to be sent to the given window (until one of PaintDC objects is destructed by garbage collector). To solve this problem one has to .skip the event passed to EVT_PAINT handler, while setting Wx::BG_STYLE_CUSTOM as a background style for the window. Maybe alternative solution could be created, i.e hand crafting swig''ged ''paint'' function taking a ruby block, which creates the PaintDC, yields it to the block, and destructs it before leaving the function? A.K.
Artur Kuptel wrote:> When implementing EVT_PAINT handlers in c++ the PaintDC object is > constructed at the beginning of the function, > and auto destructed at it''s end, which informs wxwidgets that "invalid > regions in the window have been repainted". > Under ruby, this is not the case and causes a stream of EVT_PAINT events > to be sent to the given window (until one > of PaintDC objects is destructed by garbage collector).I''ve seen that stream of EVT_PAINT events on Windows but hadn''t realised that was the cause. Interesting.> Maybe alternative solution could be created, i.e hand crafting swig''ged > ''paint'' function taking a ruby block, > which creates the PaintDC, yields it to the block, and destructs it > before leaving the function? >In fact this is how it worked up until 0.0.37 - in 0.0.36 swig/Window.i there was the following in an %extend block: VALUE paint() { wxWindow *ptr = self; if(rb_block_given_p()) { wxPaintDC dc(ptr); VALUE dcVal = SWIG_NewPointerObj((void *) &dc, SWIGTYPE_p_wxPaintDC, 0); rb_yield(dcVal); DATA_PTR(dcVal) = NULL; } return Qnil; } However, this was causing ObjectPreviouslyDeleted errors so we moved it into Ruby in classes/window.rb, unaware that the timely destruction of the C++ DC object was important. We could certainly try this approach again - perhaps all we need to do in addition is ensure SWIG''s object tracking is switched off for DC objects, as they should never be stored? alex
Alex Fenton wrote:> In fact this is how it worked up until 0.0.37 - in 0.0.36 swig/Window.i > there was the following in an %extend block: > > VALUE paint() > { > wxWindow *ptr = self; > > if(rb_block_given_p()) > { > wxPaintDC dc(ptr); > > VALUE dcVal = SWIG_NewPointerObj((void *) &dc, > SWIGTYPE_p_wxPaintDC, 0); > rb_yield(dcVal); > > DATA_PTR(dcVal) = NULL; > } > return Qnil; > } > > However, this was causing ObjectPreviouslyDeleted errors so we moved it > into Ruby in classes/window.rb, unaware that the timely destruction of > the C++ DC object was important. > >This seems to be caused by creating the PaintDC object on the stack, (consecutive calls get the same SP) SWIG_NewPointerObj() is registering &dc in the tracking hash table, after DATA_PTR(dcVal) = NULL, the next call to SWIG_NewPointerObj() function finds the &dc pointer in the hash table, but sees it is already deleted and ObjectPreviouslyDeleted happens. Attached patch seems to fix the problem. A.K. -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: win.patch Url: http://rubyforge.org/pipermail/wxruby-development/attachments/20070321/19c3eb26/attachment.pl
Artur Kuptel wrote:> This seems to be caused by creating the PaintDC object on the stack, > (consecutive calls get the same SP) > SWIG_NewPointerObj() is registering &dc in the tracking hash table, > after DATA_PTR(dcVal) = NULL, the next call to SWIG_NewPointerObj() > function > finds the &dc pointer in the hash table, but sees it is already > deleted and > ObjectPreviouslyDeleted happens. > Attached patch seems to fix the problem.Applied, thank you; also deleted the redundant ruby method. I changed it to ''if ( ruby_block_given_p )'' otherwise the block isn''t run - let me know if I''ve misunderstood. cheers alex
Alex Fenton wrote:> Applied, thank you; also deleted the redundant ruby method. > > I changed it to ''if ( ruby_block_given_p )'' otherwise the block isn''t > run - let me know if I''ve misunderstood. >That ''!'' was a remnant of my aborted attempt to change the if branch to: if(!rb_block_given_p()) return Qnil; wxPaintDC dc(ptr); VALUE dcVal = SWIG_NewPointerObj((void *) &dc,SWIGTYPE_p_wxPaintDC, 0); rb_yield(dcVal); SWIG_RubyRemoveTracking((void *) &dc); DATA_PTR(dcVal) = NULL; I''m sorry for that glitch :) A.K.
Possibly Parallel Threads
- modified classes
- ObjectPreviouslyDeleted when trying to paint
- [707] trunk/wxruby2/swig/classes/Window.i: Window-paint method now implemented in Ruby (Alex Fenton)
- [983] branches/wxruby2/wxwidgets_282: Make Window#paint work both inside and outside a paint event handler,
- [910] branches/wxruby2/wxwidgets_282: Moved paint() method back into C++, so DC object is destroyed in timely