← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3146: fix leaks related to combo boxes differently

 

------------------------------------------------------------
revno: 3146
committer: poy <poy@xxxxxxxxxx>
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;
 }