Kevin Altis wrote:
BTW, it looks like I can create a typemap that will change the code generated for handling the return of a wxBrush, etc. reference to be like the 2nd line of the C++ example above, i.e., it will create a copy to return, instead of the original reference, so then the copy-on-write will work as expected. By using a typemap I won't have to hunt down and evaluate all the places that it should be used, SWIG will do it for me. Now I just need to figure out which return types to apply the typemap to. wxBrush, wxPen, and wxFont are obvious, but what about wxBitmap, wxIcon and wxCursor? Is there any place that you would do a GetBitmap and expect to be able to operate on the original bitmap without having to do another SetBitmap later?
This whole issue probably needs more thought before a "solution" is implemented. Off the top of my head...
1. Does it only apply to classes in wxWindows that use reference counting?
The typemap can be applied to any of the following: wxBrush, wxPen, wxFont, wxBitmap, wxIcon, wxCursor, wxRegion.
2. There are instances where calling GetBrush, GetPen, etc. might return an invalid object, so at least in some cases you have to create a new object and follow-up with SetBrush, SetPen anyway.
Returning a copy will still show up as invalid (brush.Ok() returns false) but as soon as you set an attribute the copy-on-write kicks in and creates a wxBrushRefData instance for it and it then becomes valid.
3. How does wxDC::SetOptimization impact any solution? Having to special-case code for each platform in our Python apps is exactly the kind of thing we don't want, wxWindows or wxPython should be doing the work not every app programmer. Maybe SetOptimization should be off by default?!
Actually, it appears that none of the wx ports currently do anything for SetOptimization.
4. Is using Get and then changing in-place more Pythonic?
Probably, but it can't be done without recreating the native pen/brush/font (or at least tracking a 'dirty' flag) before each dc.Draw* method call. And that is overhead that the C++ folks would find unacceptable.
5. Maybe SetBrush, SetPen... shouldn't be checking pointers as the test for equivalency?
It's not. The == operator looks like this:
bool wxBrushRefData::operator==(const wxBrushRefData& data) const
{
// don't compare HBRUSHes
return m_style == data.m_style &&
m_colour == data.m_colour &&
m_stipple == data.m_stipple;
}
but since your original example ended up calling SetBrush with the same instance as was already set then the above test always returns true.
Is this in essence what SetOptimization is about?
No, I think it is supposed to be a hook for doing platform specific stuff, lower level things than wxPen, etc.
What is the real performance penalty if you set the brush or pen and the values are the same?!
A new native object is created, then a native API is called to select it into the DC and another will be called to release the old one (if it's refcount has dropped to zero), plus a bit of wx-specific overhead. So there are at least three native APIs called, plus some allocations and deallocations.
6. The code example of just changing one attribute like the color of a brush definitely needs to be simpler.
With my typemap change it will be just like you had in your sample:
brush = dc.GetBrush()
brush.SetColour("blue")
dc.SetBrush(brush)
7. I still think we should consider having additional direct wxDC methods for changing the pen color, brush color, etc.
What do you mean?
8. Are we going to get into trouble by using up scarce GDI resources on Win9x?
No, that's what the C++ ref-counting/copy-on-write design is intended to help with. You only get a new native GDI object when you create a new one from scratch, or when you change the attribute of an existing one via a second (C++) reference to it.
···
--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!