Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reversing unbind order breaks the event chain link and makes the program crash. #2027

Closed
komoto48g opened this issue Nov 16, 2021 · 5 comments · Fixed by #2029
Closed

Reversing unbind order breaks the event chain link and makes the program crash. #2027

komoto48g opened this issue Nov 16, 2021 · 5 comments · Fixed by #2029

Comments

@komoto48g
Copy link
Contributor

komoto48g commented Nov 16, 2021

Operating system: Windows 10 64bit ver 20H2
wxPython version & source: 4.1.1 (pypi)
Python version & source: 3.8.6

Description of the problem:
In the sample code, the button object only binds and unbinds the two handlers. If the unbinding order is reversed, the program will crash. I also checked it with wx.version 4.0.7, and there was no problem.

Code Example (click to expand)
import wx

class TestPanel(wx.Panel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        self.btn = wx.Button(self, label="Hello, wxPython!")
        
        self.btn.Bind(wx.EVT_BUTTON, self.onButton1)
        self.btn.Bind(wx.EVT_BUTTON, self.onButton2)
        
        if 0:
            ## no problem
            self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton2)
            self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton1)
        else:
            ## eversing the unbind order will break the linkage of the event chain
            self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton1)
            self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton2)
    
    def onButton1(self, evt):
        print(1)
        evt.Skip()
    
    def onButton2(self, evt):
        print(2)
        evt.Skip()

app = wx.App()
frm = wx.Frame(None)
frm.panel = TestPanel(frm)
frm.Show()
app.MainLoop()
@RobinD42
Copy link
Member

This issue has been mentioned on Discuss wxPython. There might be relevant details there:

https://discuss.wxpython.org/t/problem-with-event-watcher/35647/2

@swt2c
Copy link
Collaborator

swt2c commented Nov 17, 2021

Confirmed.

swt2c added a commit to swt2c/Phoenix that referenced this issue Nov 18, 2021
When binding events to multiple methods and then unbinding them later,
in the same order they were bound, the wrong method would get unbound.

For example:
    self.btn.Bind(wx.EVT_BUTTON, self.onButton1)
    self.btn.Bind(wx.EVT_BUTTON, self.onButton1)
followed by:
    self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton2)
    self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton1)
works, but the reverse fails:
    self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton1)
    self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton2)

The reason is that the wxPython Disconnect() method called the wxWidgets
Disconnect() method with the userData parameter set to NULL.  In this
case, wxWidgets performs no filtering based on the userData parameter
and this could result in the wrong handler getting disconnected.

Fix this by setting the userData to a known value before calling
wxWidgets Disconnect() method so that it will disconnect the correct
handler.

This commit also adds a test that verifies the fix.

Fixes wxWidgets#2027.
@komoto48g
Copy link
Contributor Author

Thank you very much for PR!

@swt2c
Copy link
Collaborator

swt2c commented Nov 18, 2021

Let's leave this open until merged.

@swt2c swt2c reopened this Nov 18, 2021
@RobinD42
Copy link
Member

This issue has been mentioned on Discuss wxPython. There might be relevant details there:

https://discuss.wxpython.org/t/issue-with-unbind-of-an-event/35846/2

stahta01 pushed a commit to stahta01/wxPythonPhoenix that referenced this issue Jun 20, 2022
When binding events to multiple methods and then unbinding them later,
in the same order they were bound, the wrong method would get unbound.

For example:
    self.btn.Bind(wx.EVT_BUTTON, self.onButton1)
    self.btn.Bind(wx.EVT_BUTTON, self.onButton1)
followed by:
    self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton2)
    self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton1)
works, but the reverse fails:
    self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton1)
    self.btn.Unbind(wx.EVT_BUTTON, handler=self.onButton2)

The reason is that the wxPython Disconnect() method called the wxWidgets
Disconnect() method with the userData parameter set to NULL.  In this
case, wxWidgets performs no filtering based on the userData parameter
and this could result in the wrong handler getting disconnected.

Fix this by setting the userData to a known value before calling
wxWidgets Disconnect() method so that it will disconnect the correct
handler.

This commit also adds a test that verifies the fix.

Fixes wxWidgets#2027.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants