------------------------------------------------------------ revno: 3146 committer: poy <p...@123gen.com> branch nick: trunk timestamp: Tue 2012-11-27 21:54:06 +0100 message: fix leaks related to combo boxes differently modified: dwt/include/dwt/Widget.h dwt/include/dwt/WidgetCreator.h dwt/src/Widget.cpp dwt/src/widgets/ComboBox.cpp
-- lp:dcplusplus https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk Your team Dcplusplus-team is subscribed to branch lp:dcplusplus. To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'dwt/include/dwt/Widget.h' --- dwt/include/dwt/Widget.h 2012-11-25 18:27:27 +0000 +++ dwt/include/dwt/Widget.h 2012-11-27 20:54:06 +0000 @@ -165,9 +165,8 @@ /** * Attaches the instance to an existing window. - * @return the previous window proc, if there was one. */ - WNDPROC setHandle(HWND hwnd); + void setHandle(HWND hwnd); /// get the top-most parent window of this widget (either a main window or a modal dialog). Widget* getRoot() const; === modified file 'dwt/include/dwt/WidgetCreator.h' --- dwt/include/dwt/WidgetCreator.h 2012-11-25 18:27:27 +0000 +++ dwt/include/dwt/WidgetCreator.h 2012-11-27 20:54:06 +0000 @@ -85,9 +85,7 @@ static typename WidgetType::ObjectType attach(Widget* parent, HWND hwnd) { typename WidgetType::ObjectType w(new WidgetType(parent)); - auto proc = w->setHandle(hwnd); - // "detach" from the window before the parent is destroyed. - parent->onDestroy([=] { ::SetWindowLongPtr(w->handle(), GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(proc)); w->kill(); }); + w->setHandle(hwnd); return w; } }; === modified file 'dwt/src/Widget.cpp' --- dwt/src/Widget.cpp 2012-11-25 18:27:27 +0000 +++ dwt/src/Widget.cpp 2012-11-27 20:54:06 +0000 @@ -55,16 +55,27 @@ GlobalAtom Widget::propAtom(_T("dwt::Widget*")); +#ifdef _DEBUG +int widgetCount; +#endif + Widget::Widget(Widget* parent_, Dispatcher& dispatcher_) : hwnd(NULL), parent(parent_), dispatcher(dispatcher_) { - +#ifdef _DEBUG + ++widgetCount; + printf("created a dwt widget; count: %d\n", widgetCount); +#endif } Widget::~Widget() { if(hwnd) { ::RemoveProp(hwnd, propAtom); } +#ifdef _DEBUG + --widgetCount; + printf("destroying a dwt widget; count: %d\n", widgetCount); +#endif } void Widget::kill() { @@ -84,7 +95,7 @@ return hWnd; } -WNDPROC Widget::setHandle(HWND h) { +void Widget::setHandle(HWND h) { if(hwnd) { throw DWTException("You may not attach to a widget that's already attached"); } @@ -93,7 +104,7 @@ ::SetProp(hwnd, propAtom, reinterpret_cast<HANDLE>(this)); - return reinterpret_cast<WNDPROC>(::SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc::wndProc))); + ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc::wndProc)); } Widget* Widget::getRoot() const { === modified file 'dwt/src/widgets/ComboBox.cpp' --- dwt/src/widgets/ComboBox.cpp 2012-11-25 18:27:27 +0000 +++ dwt/src/widgets/ComboBox.cpp 2012-11-27 20:54:06 +0000 @@ -76,8 +76,15 @@ ComboBox::DropListBoxPtr ComboBox::getListBox() { if(!listBox) { COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - if(::GetComboBoxInfo(handle(), &info) && info.hwndList && info.hwndList != handle()) + if(::GetComboBoxInfo(handle(), &info) && info.hwndList && info.hwndList != handle()) { + /* unlike other controls, the list window doesn't send/receive WM_DESTROY/WN_NCDESTROY. + as a result, the listBox widget leaks. the workaround is to "detach" from the list (by + giving it back its initial window procedure) when the combo is being destroyed. */ + auto proc = ::GetWindowLongPtr(info.hwndList, GWLP_WNDPROC); listBox = WidgetCreator<DropListBox>::attach(this, info.hwndList); + listBox->onDestroy([this] { listBox = nullptr; }); + onDestroy([this, proc] { if(listBox) { ::SetWindowLongPtr(listBox->handle(), GWLP_WNDPROC, proc); listBox->kill(); } }); + } } return listBox; } @@ -85,8 +92,14 @@ TextBoxPtr ComboBox::getTextBox() { if(!textBox) { COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - if(::GetComboBoxInfo(handle(), &info) && info.hwndItem && info.hwndItem != handle()) + if(::GetComboBoxInfo(handle(), &info) && info.hwndItem && info.hwndItem != handle()) { + /* combo edits do receive destruction messages, but we do the same crap as for lists + to be on the safe side. */ + auto proc = ::GetWindowLongPtr(info.hwndItem, GWLP_WNDPROC); textBox = WidgetCreator<TextBox>::attach(this, info.hwndItem); + textBox->onDestroy([this] { textBox = nullptr; }); + onDestroy([this, proc] { if(textBox) { ::SetWindowLongPtr(textBox->handle(), GWLP_WNDPROC, proc); textBox->kill(); } }); + } } return textBox; }
_______________________________________________ Mailing list: https://launchpad.net/~linuxdcpp-team Post to : linuxdcpp-team@lists.launchpad.net Unsubscribe : https://launchpad.net/~linuxdcpp-team More help : https://help.launchpad.net/ListHelp