Merge pull request #1201 from RobinD42/fix-issue1198

Fix access to members of transient wx.VisualAttributes

(cherry picked from commit d6324a0578)
This commit is contained in:
Robin Dunn
2019-04-13 16:24:46 -07:00
parent f0e0d80dd8
commit 0378328d45
7 changed files with 89 additions and 9 deletions

View File

@@ -61,7 +61,10 @@ Changes in this release include the following:
* Fix the use of the output parameter in HtmlWindow.OnOpeningURL the same way
it was fixed in HtmlWindowInterface.OnHTMLOpeningURL. (#1068)
* Fixed a crashing bug when using a member of a transient wx.VisualAttributes
object. Also set the attributes to be read-only to simplify the fix. (#1198).

View File

@@ -46,7 +46,6 @@ def run():
c = module.find('wxProgressDialog')
tools.fixWindowClass(c)
# Copy methods from the generic to the native class. This is needed
# because none of the methods are declared in the interface files, and
@@ -59,6 +58,7 @@ def run():
not item.isDtor):
c.addItem(copy.deepcopy(item))
tools.fixWindowClass(c)
#-----------------------------------------------------------------
tools.doCommonTweaks(module)

View File

@@ -35,6 +35,29 @@ def run():
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxVisualAttributes')
assert isinstance(c, etgtools.ClassDef)
# Mark the stucture memebers as read-only, and make copies of the values
# when fetching them. This is to protect against cases where the
# VisualAttributes object is transient and may be GC'd while we still are
# using a reference to a C++ member value.
c.find('colBg').noSetter = True
c.find('colBg').getCode = """\
wxColour* clr = new wxColour(sipCpp->colBg);
sipPy = wxPyConstructObject((void*)clr, "wxColour", true);
"""
c.find('colFg').noSetter = True
c.find('colFg').getCode = """\
wxColour* clr = new wxColour(sipCpp->colFg);
sipPy = wxPyConstructObject((void*)clr, "wxColour", true);
"""
c.find('font').noSetter = True
c.find('font').getCode = """\
wxFont* font = new wxFont(sipCpp->font);
sipPy = wxPyConstructObject((void*)font, "wxFont", true);
"""
c = module.find('wxWindow')
assert isinstance(c, etgtools.ClassDef)
module.addGlobalStr('wxPanelNameStr', c)

View File

@@ -206,6 +206,7 @@ class VariableDef(BaseDef):
self.definition = ''
self.argsString = ''
self.pyInt = False
self.noSetter = False
self.__dict__.update(**kw)
if element is not None:
self.extract(element)
@@ -247,6 +248,8 @@ class MemberVarDef(VariableDef):
super(MemberVarDef, self).__init__()
self.isStatic = False
self.protection = 'public'
self.getCode = ''
self.setCode = ''
self.__dict__.update(kw)
if element is not None:
self.extract(element)

View File

@@ -569,7 +569,19 @@ from .%s import *
if memberVar.ignored:
return
stream.write('%s%s %s' % (indent, memberVar.type, memberVar.name))
stream.write('%s;\n\n' % self.annotate(memberVar))
stream.write(self.annotate(memberVar))
if memberVar.getCode or memberVar.setCode:
stream.write('\n%s{\n' % (indent,))
if memberVar.getCode:
stream.write('%s%%GetCode\n' % (indent))
stream.write(nci(memberVar.getCode, len(indent)+4))
stream.write('%s%%End\n' % (indent))
if memberVar.setCode:
stream.write('%s%%SetCode\n' % (indent))
stream.write(nci(memberVar.setCode, len(indent)+4))
stream.write('%s%%End\n' % (indent))
stream.write('%s}' % (indent,))
stream.write(';\n\n')
def generateProperty(self, prop, stream, indent):
@@ -979,6 +991,8 @@ from .%s import *
if isinstance(item, extractors.VariableDef):
if item.pyInt:
annotations.append('PyInt')
if item.noSetter:
annotations.append('NoSetter')
if isinstance(item, extractors.TypedefDef):
if item.noTypeName:

View File

@@ -261,17 +261,27 @@ def fixWindowClass(klass, hideVirtuals=True, ignoreProtected=True):
removeVirtuals(klass)
addWindowVirtuals(klass)
if not klass.findItem('GetClassDefaultAttributes'):
klass.addItem(extractors.WigCode("""\
static wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
"""))
if not ignoreProtected:
for item in klass.allItems():
if isinstance(item, extractors.MethodDef) and item.protection == 'protected':
item.ignore(False)
fixDefaultAttributesMethods(klass)
def fixDefaultAttributesMethods(klass):
if not klass.findItem('GetClassDefaultAttributes'):
m = extractors.MethodDef(
type='wxVisualAttributes', name='GetClassDefaultAttributes',
isStatic=True, protection='public',
items=[extractors.ParamDef(
type='wxWindowVariant', name='variant', default='wxWINDOW_VARIANT_NORMAL')]
)
klass.addItem(m)
if klass.findItem('GetDefaultAttributes'):
klass.find('GetDefaultAttributes').mustHaveApp()
klass.find('GetClassDefaultAttributes').mustHaveApp()
def fixTopLevelWindowClass(klass, hideVirtuals=True, ignoreProtected=True):
@@ -308,6 +318,8 @@ def fixTopLevelWindowClass(klass, hideVirtuals=True, ignoreProtected=True):
if isinstance(item, extractors.MethodDef) and item.protection == 'protected':
item.ignore(False)
fixDefaultAttributesMethods(klass)
def fixSizerClass(klass):

View File

@@ -137,6 +137,31 @@ class WindowTests(wtc.WidgetTestCase):
wx.DLG_PNT
def test_vizattrs1(self):
w = wx.Window(self.frame, -1, (10,10), (50,50))
a = w.GetClassDefaultAttributes()
assert isinstance(a.colBg, wx.Colour)
assert isinstance(a.colFg, wx.Colour)
assert isinstance(a.font, wx.Font)
def test_vizattrs2(self):
w = wx.Window(self.frame, -1, (10,10), (50,50))
assert isinstance(w.GetClassDefaultAttributes().colBg, wx.Colour)
assert isinstance(w.GetClassDefaultAttributes().colFg, wx.Colour)
assert isinstance(w.GetClassDefaultAttributes().font, wx.Font)
def test_vizattrs3(self):
w = wx.Window(self.frame, -1, (10,10), (50,50))
a = w.GetClassDefaultAttributes()
with self.assertRaises(AttributeError):
a.colBg = wx.Colour('blue')
with self.assertRaises(AttributeError):
a.colFg = wx.Colour('blue')
with self.assertRaises(AttributeError):
a.font = wx.NORMAL_FONT
#---------------------------------------------------------------------------