← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2811: fix mingw build by moving mappers to dcpp; simplify the cshelp popup and mess around with the set...

 

------------------------------------------------------------
revno: 2811
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Wed 2012-01-11 22:42:27 +0100
message:
  fix mingw build by moving mappers to dcpp; simplify the cshelp popup and mess around with the settings dialog
renamed:
  win32/Mapper_MiniUPnPc.cpp => dcpp/Mapper_MiniUPnPc.cpp
  win32/Mapper_MiniUPnPc.h => dcpp/Mapper_MiniUPnPc.h
  win32/Mapper_NATPMP.cpp => dcpp/Mapper_NATPMP.cpp
  win32/Mapper_NATPMP.h => dcpp/Mapper_NATPMP.h
  win32/Mapper_WinUPnP.cpp => dcpp/Mapper_WinUPnP.cpp
  win32/Mapper_WinUPnP.h => dcpp/Mapper_WinUPnP.h
modified:
  dcpp/Mapper.cpp
  dcpp/MappingManager.cpp
  dcpp/MappingManager.h
  dwt/include/dwt/aspects/Columns.h
  dwt/include/dwt/widgets/Table.h
  dwt/include/dwt/widgets/ToolTip.h
  dwt/src/widgets/ToolTip.cpp
  utils/portmap.cpp
  win32/HashProgressDlg.cpp
  win32/SettingsDialog.cpp
  win32/SettingsDialog.h
  win32/StylesPage.cpp
  win32/WinUtil.cpp
  win32/WinUtil.h
  win32/forward.h
  win32/main.cpp
  dcpp/Mapper_MiniUPnPc.cpp
  dcpp/Mapper_MiniUPnPc.h
  dcpp/Mapper_NATPMP.cpp
  dcpp/Mapper_NATPMP.h
  dcpp/Mapper_WinUPnP.cpp
  dcpp/Mapper_WinUPnP.h


--
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 'dcpp/Mapper.cpp'
--- dcpp/Mapper.cpp	2011-10-22 16:41:13 +0000
+++ dcpp/Mapper.cpp	2012-01-11 21:42:27 +0000
@@ -17,8 +17,6 @@
  */
 
 #include "stdinc.h"
-#include "DCPlusPlus.h"
-
 #include "Mapper.h"
 
 namespace dcpp {

=== renamed file 'win32/Mapper_MiniUPnPc.cpp' => 'dcpp/Mapper_MiniUPnPc.cpp'
--- win32/Mapper_MiniUPnPc.cpp	2012-01-01 20:42:31 +0000
+++ dcpp/Mapper_MiniUPnPc.cpp	2012-01-11 21:42:27 +0000
@@ -16,13 +16,12 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include "stdafx.h"
-
+#include "stdinc.h"
 #include "Mapper_MiniUPnPc.h"
 
-#include <dcpp/ConnectivityManager.h>
-#include <dcpp/SettingsManager.h>
-#include <dcpp/Util.h>
+#include "ConnectivityManager.h"
+#include "SettingsManager.h"
+#include "Util.h"
 
 extern "C" {
 #ifndef STATICLIB
@@ -32,6 +31,8 @@
 #include <miniupnpc/upnpcommands.h>
 }
 
+namespace dcpp {
+
 const string Mapper_MiniUPnPc::name = "MiniUPnP";
 
 bool Mapper_MiniUPnPc::init() {
@@ -95,3 +96,5 @@
 		return buf;
 	return Util::emptyString;
 }
+
+} // dcpp namespace

=== renamed file 'win32/Mapper_MiniUPnPc.h' => 'dcpp/Mapper_MiniUPnPc.h'
--- win32/Mapper_MiniUPnPc.h	2011-10-22 16:41:13 +0000
+++ dcpp/Mapper_MiniUPnPc.h	2012-01-11 21:42:27 +0000
@@ -16,10 +16,12 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#ifndef DCPLUSPLUS_WIN32_MAPPER_MINIUPNPC_H
-#define DCPLUSPLUS_WIN32_MAPPER_MINIUPNPC_H
-
-#include <dcpp/Mapper.h>
+#ifndef DCPLUSPLUS_DCPP_MAPPER_MINIUPNPC_H
+#define DCPLUSPLUS_DCPP_MAPPER_MINIUPNPC_H
+
+#include "Mapper.h"
+
+namespace dcpp {
 
 class Mapper_MiniUPnPc : public Mapper
 {
@@ -47,4 +49,6 @@
 	string device;
 };
 
+} // dcpp namespace
+
 #endif

=== renamed file 'win32/Mapper_NATPMP.cpp' => 'dcpp/Mapper_NATPMP.cpp'
--- win32/Mapper_NATPMP.cpp	2011-11-04 16:30:55 +0000
+++ dcpp/Mapper_NATPMP.cpp	2012-01-11 21:42:27 +0000
@@ -16,11 +16,10 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include "stdafx.h"
-
+#include "stdinc.h"
 #include "Mapper_NATPMP.h"
 
-#include <dcpp/Util.h>
+#include "Util.h"
 
 extern "C" {
 #ifndef STATICLIB
@@ -30,6 +29,8 @@
 #include <natpmp/natpmp.h>
 }
 
+namespace dcpp {
+
 const string Mapper_NATPMP::name = "NAT-PMP";
 
 static natpmp_t nat;
@@ -125,3 +126,5 @@
 	}
 	return Util::emptyString;
 }
+
+} // dcpp namespace

=== renamed file 'win32/Mapper_NATPMP.h' => 'dcpp/Mapper_NATPMP.h'
--- win32/Mapper_NATPMP.h	2011-10-22 16:41:13 +0000
+++ dcpp/Mapper_NATPMP.h	2012-01-11 21:42:27 +0000
@@ -16,11 +16,13 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#ifndef DCPLUSPLUS_WIN32_MAPPER_NATPMP_H
-#define DCPLUSPLUS_WIN32_MAPPER_NATPMP_H
+#ifndef DCPLUSPLUS_DCPP_MAPPER_NATPMP_H
+#define DCPLUSPLUS_DCPP_MAPPER_NATPMP_H
 
 #include <dcpp/Mapper.h>
 
+namespace dcpp {
+
 class Mapper_NATPMP : public Mapper
 {
 public:
@@ -46,4 +48,6 @@
 	uint32_t lifetime;
 };
 
+} // dcpp namespace
+
 #endif

=== renamed file 'win32/Mapper_WinUPnP.cpp' => 'dcpp/Mapper_WinUPnP.cpp'
--- win32/Mapper_WinUPnP.cpp	2012-01-01 20:42:31 +0000
+++ dcpp/Mapper_WinUPnP.cpp	2012-01-11 21:42:27 +0000
@@ -16,20 +16,24 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include "stdafx.h"
-
+#include "stdinc.h"
 #include "Mapper_WinUPnP.h"
 
-#include <dcpp/Util.h>
-#include <dcpp/Text.h>
+#include "Util.h"
+#include "Text.h"
+#include "w.h"
 
+#ifdef HAVE_NATUPNP_H
 #include <ole2.h>
+#include <natupnp.h>
+#endif // HAVE_NATUPNP_H
+
+namespace dcpp {
 
 const string Mapper_WinUPnP::name = "Windows UPnP";
 
 #ifdef HAVE_NATUPNP_H
-#include <natupnp.h>
-	
+
 bool Mapper_WinUPnP::init() {
 	HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 	if(FAILED(hr))
@@ -170,7 +174,10 @@
 	return ret;
 }
 
-#else
+#else // HAVE_NATUPNP_H
+
+struct IUPnPNAT { };
+struct IStaticPortMappingCollection { };
 
 bool Mapper_WinUPnP::init() {
 	return false;
@@ -199,4 +206,6 @@
 	return 0;
 }
 
-#endif
+#endif // HAVE_NATUPNP_H
+
+} // dcpp namespace

=== renamed file 'win32/Mapper_WinUPnP.h' => 'dcpp/Mapper_WinUPnP.h'
--- win32/Mapper_WinUPnP.h	2011-10-22 16:41:13 +0000
+++ dcpp/Mapper_WinUPnP.h	2012-01-11 21:42:27 +0000
@@ -16,14 +16,16 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#ifndef DCPLUSPLUS_WIN32_MAPPER_WINUPNP_H
-#define DCPLUSPLUS_WIN32_MAPPER_WINUPNP_H
+#ifndef DCPLUSPLUS_DCPP_MAPPER_WINUPNP_H
+#define DCPLUSPLUS_DCPP_MAPPER_WINUPNP_H
 
-#include <dcpp/Mapper.h>
+#include "Mapper.h"
 
 struct IUPnPNAT;
 struct IStaticPortMappingCollection;
 
+namespace dcpp {
+
 /// @todo this class is far from complete (should register callbacks, etc)
 class Mapper_WinUPnP : public Mapper
 {
@@ -55,4 +57,6 @@
 	Protocol lastProtocol;
 };
 
+} // dcpp namespace
+
 #endif

=== modified file 'dcpp/MappingManager.cpp'
--- dcpp/MappingManager.cpp	2011-12-08 18:01:40 +0000
+++ dcpp/MappingManager.cpp	2012-01-11 21:42:27 +0000
@@ -23,12 +23,23 @@
 #include "ConnectivityManager.h"
 #include "format.h"
 #include "LogManager.h"
+#include "Mapper_MiniUPnPc.h"
+#include "Mapper_NATPMP.h"
+#include "Mapper_WinUPnP.h"
 #include "ScopedFunctor.h"
 #include "SearchManager.h"
 #include "version.h"
 
 namespace dcpp {
 
+MappingManager::MappingManager() : busy(false), renewal(0) {
+	addMapper<Mapper_NATPMP>();
+	addMapper<Mapper_MiniUPnPc>();
+#ifdef HAVE_NATUPNP_H
+	addMapper<Mapper_WinUPnP>();
+#endif
+}
+
 StringList MappingManager::getMappers() const {
 	StringList ret;
 	for(auto i = mappers.cbegin(), iend = mappers.cend(); i != iend; ++i)

=== modified file 'dcpp/MappingManager.h'
--- dcpp/MappingManager.h	2011-12-27 20:06:53 +0000
+++ dcpp/MappingManager.h	2012-01-11 21:42:27 +0000
@@ -32,6 +32,7 @@
 namespace dcpp {
 
 using std::function;
+using std::make_pair;
 using std::unique_ptr;
 using std::vector;
 
@@ -59,7 +60,7 @@
 	unique_ptr<Mapper> working; /// currently working implementation.
 	uint64_t renewal; /// when the next renewal should happen, if requested by the mapper.
 
-	MappingManager() : busy(false), renewal(0) { }
+	MappingManager();
 	virtual ~MappingManager() { }
 
 	int run();

=== modified file 'dwt/include/dwt/aspects/Columns.h'
--- dwt/include/dwt/aspects/Columns.h	2012-01-08 22:14:11 +0000
+++ dwt/include/dwt/aspects/Columns.h	2012-01-11 21:42:27 +0000
@@ -126,7 +126,7 @@
 template<typename WidgetType>
 inline void Columns<WidgetType>::setColumns(const std::vector<Column>& columns) {
 	for(auto i = 0u, iend = getColumnCount(); i < iend; ++i) eraseColumn(i);
-	for(auto i = 0u, iend = columns.size(); i < iend; ++i) insertColumn(columns[i], i);
+	for(size_t i = 0, iend = columns.size(); i < iend; ++i) insertColumn(columns[i], i);
 }
 
 template<typename WidgetType>

=== modified file 'dwt/include/dwt/widgets/Table.h'
--- dwt/include/dwt/widgets/Table.h	2012-01-08 22:14:11 +0000
+++ dwt/include/dwt/widgets/Table.h	2012-01-11 21:42:27 +0000
@@ -618,7 +618,7 @@
 }
 
 inline void Table::setColumnOrderImpl(const std::vector<int>& columns) {
-	::SendMessage(handle(), LVM_SETCOLUMNORDERARRAY, static_cast<WPARAM>(columns.size()), reinterpret_cast<LPARAM>(&columns[0])) > 0;
+	sendMessage(LVM_SETCOLUMNORDERARRAY, static_cast<WPARAM>(columns.size()), reinterpret_cast<LPARAM>(&columns[0]));
 }
 
 inline void Table::setTableStyle(int style) {

=== modified file 'dwt/include/dwt/widgets/ToolTip.h'
--- dwt/include/dwt/widgets/ToolTip.h	2011-12-23 14:07:18 +0000
+++ dwt/include/dwt/widgets/ToolTip.h	2012-01-11 21:42:27 +0000
@@ -73,6 +73,7 @@
 
 	void setText(const tstring& text_);
 	void setText(Widget* widget, const tstring& text);
+	void addTool(Widget* widget);
 	void setTool(Widget* widget, F callback);
 
 	void setMaxTipWidth(int width);
@@ -101,8 +102,6 @@
 	tstring text;
 
 private:
-	void handleGetTip(tstring& ret);
-
 	friend class ChainingDispatcher;
 	static const TCHAR windowClass[];
 };

=== modified file 'dwt/src/widgets/ToolTip.cpp'
--- dwt/src/widgets/ToolTip.cpp	2011-12-23 14:07:18 +0000
+++ dwt/src/widgets/ToolTip.cpp	2012-01-11 21:42:27 +0000
@@ -57,18 +57,21 @@
 
 void ToolTip::setText(Widget* widget, const tstring& text_) {
 	text = text_;
-	setTool(widget, [this](tstring& t) { handleGetTip(t); });
+	setTool(widget, [this](tstring& ret) { ret = text; });
 }
 
-void ToolTip::setTool(Widget* widget, F f) {
-	onGetTip(f);
-
+void ToolTip::addTool(Widget* widget) {
 	TOOLINFO ti = { sizeof(TOOLINFO), TTF_IDISHWND | TTF_SUBCLASS, getParent()->handle(),
 		reinterpret_cast<UINT_PTR>(widget->handle()) };
 	ti.lpszText = LPSTR_TEXTCALLBACK;
 	sendMessage(TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&ti));
 }
 
+void ToolTip::setTool(Widget* widget, F f) {
+	onGetTip(f);
+	addTool(widget);
+}
+
 void ToolTip::setActive(bool b) {
 	sendMessage(TTM_ACTIVATE, b ? TRUE : FALSE);
 }
@@ -90,8 +93,4 @@
 	});
 }
 
-void ToolTip::handleGetTip(tstring& ret) {
-	ret = text;
-}
-
 }

=== modified file 'utils/portmap.cpp'
--- utils/portmap.cpp	2012-01-01 20:42:31 +0000
+++ utils/portmap.cpp	2012-01-11 21:42:27 +0000
@@ -40,9 +40,9 @@
 	return tmp;
 }
 
-#include <win32/Mapper_MiniUPnPc.cpp>
-#include <win32/Mapper_NATPMP.cpp>
-#include <win32/Mapper_WinUPnP.cpp>
+#include <dcpp/Mapper_MiniUPnPc.cpp>
+#include <dcpp/Mapper_NATPMP.cpp>
+#include <dcpp/Mapper_WinUPnP.cpp>
 
 void help() {
 	cout << "Arguments to run portmap with:" << endl << "\t portmap <port> <type> <description> <method> [remove]" << endl

=== modified file 'win32/HashProgressDlg.cpp'
--- win32/HashProgressDlg.cpp	2011-12-19 16:46:55 +0000
+++ win32/HashProgressDlg.cpp	2012-01-11 21:42:27 +0000
@@ -132,7 +132,7 @@
 
 	if(autoClose && files == 0) {
 		close(true);
-		return true;
+		return false;
 	}
 
 	file->setText(files ? Text::toT(path) : T_("Done"));

=== modified file 'win32/SettingsDialog.cpp'
--- win32/SettingsDialog.cpp	2011-12-22 22:14:45 +0000
+++ win32/SettingsDialog.cpp	2012-01-11 21:42:27 +0000
@@ -27,6 +27,7 @@
 #include <dwt/util/GDI.h>
 #include <dwt/widgets/Grid.h>
 #include <dwt/widgets/ScrolledContainer.h>
+#include <dwt/widgets/ToolTip.h>
 
 #include "WinUtil.h"
 
@@ -63,12 +64,15 @@
 using dwt::Grid;
 using dwt::GridInfo;
 
+using dwt::ToolTip;
+
 SettingsDialog::SettingsDialog(dwt::Widget* parent) :
 dwt::ModalDialog(parent),
 currentPage(0),
 grid(0),
 tree(0),
-help(0)
+help(0),
+tip(0)
 {
 	onInitDialog([this] { return initDialog(); });
 	onHelp([this](Control* c, unsigned id) { handleHelp(c, id); });
@@ -211,6 +215,19 @@
 		WinUtil::addHelpButton(cur)->onClicked([this] { handleHelp(this, IDH_INDEX); });
 	}
 
+	/* use a hidden tooltip to determine when to show the help tooltip, so we don't have to manage
+	timers etc. */
+	tip = addChild(ToolTip::Seed());
+	auto timeout = tip->sendMessage(TTM_GETDELAYTIME, TTDT_AUTOPOP);
+	tip->addCallback(dwt::Message(WM_NOTIFY, TTN_GETDISPINFO), [timeout](const MSG& msg, LRESULT&) -> bool {
+		auto& ttdi = *reinterpret_cast<LPNMTTDISPINFO>(msg.lParam);
+		auto widget = dwt::hwnd_cast<dwt::Control*>(reinterpret_cast<HWND>(ttdi.hdr.idFrom));
+		if(widget) {
+			WinUtil::helpTooltip(widget, timeout);
+		}
+		return true;
+	});
+
 	/*
 	* catch WM_SETFOCUS messages (onFocus events) sent to every children of this dialog. the normal
 	* way to do it would be to use an Application::Filter, but unfortunately these messages don't
@@ -234,11 +251,19 @@
 BOOL CALLBACK SettingsDialog::EnumChildProc(HWND hwnd, LPARAM lParam) {
 	SettingsDialog* dialog = reinterpret_cast<SettingsDialog*>(lParam);
 	dwt::Control* widget = dwt::hwnd_cast<dwt::Control*>(hwnd);
+
 	if(widget && widget != dialog->help) {
 		widget->onFocus([=] { dialog->handleChildHelp(widget); });
+
 		TablePtr table = dynamic_cast<TablePtr>(widget);
 		if(table)
 			table->onSelectionChanged([=] { dialog->handleChildHelp(widget); });
+
+		auto id = widget->getHelpId();
+		if(id >= IDH_CSHELP_BEGIN && id <= IDH_CSHELP_END) {
+			// this widget has a valid cshelp id; associate a tooltip tool to it.
+			dialog->tip->addTool(widget);
+		}
 	}
 	return TRUE;
 }

=== modified file 'win32/SettingsDialog.h'
--- win32/SettingsDialog.h	2011-12-04 15:13:29 +0000
+++ win32/SettingsDialog.h	2012-01-11 21:42:27 +0000
@@ -24,6 +24,7 @@
 #include <dwt/widgets/ModalDialog.h>
 #include <dwt/widgets/Tree.h>
 
+#include "forward.h"
 #include "PropPage.h"
 
 class SettingsDialog : public dwt::ModalDialog
@@ -65,6 +66,7 @@
 	GridPtr grid;
 	TreePtr tree;
 	RichTextBoxPtr help;
+	ToolTipPtr tip;
 
 	void updateTitle();
 	void write();

=== modified file 'win32/StylesPage.cpp'
--- win32/StylesPage.cpp	2011-12-22 22:14:45 +0000
+++ win32/StylesPage.cpp	2012-01-11 21:42:27 +0000
@@ -188,7 +188,7 @@
 }
 
 void StylesPage::updateUserMatches(std::vector<UserMatch>& userMatches) {
-	for(auto i = 0; i < table->size();) {
+	for(size_t i = 0; i < table->size();) {
 		auto data = table->getData(i);
 		if(data == noUserMatchData) {
 			table->erase(i);

=== modified file 'win32/WinUtil.cpp'
--- win32/WinUtil.cpp	2012-01-08 22:14:11 +0000
+++ win32/WinUtil.cpp	2012-01-11 21:42:27 +0000
@@ -891,115 +891,118 @@
 	return false;
 }
 
-class HelpPopup: public Container {
-	typedef Container BaseType;
+template<bool tooltip>
+class HelpPopup : private RichTextBox {
+	typedef HelpPopup<tooltip> ThisType;
+	typedef RichTextBox BaseType;
 
 public:
-	explicit HelpPopup(dwt::Control* parent, const tstring& text_) :
-		BaseType(parent, dwt::NormalDispatcher::newClass<HelpPopup>(0, 0, dwt::Dispatcher::getDefaultCursor(),
-			reinterpret_cast<HBRUSH> (COLOR_INFOBK + 1))), text(text_)
+	HelpPopup(dwt::Widget* parent, const tstring& text, unsigned timeout = 0, bool multiline = false) :
+		BaseType(parent), text(text), timeout(timeout)
 	{
-		// where to position the tooltip
+		// where to position the popup.
 		dwt::Point pt;
 		if(isKeyPressed(VK_F1)) {
-			dwt::Rectangle rect = parent->getWindowRect();
+			auto rect = parent->getWindowRect();
 			pt.x = rect.left() + rect.width() / 2;
 			pt.y = rect.top();
 		} else {
 			pt = dwt::Point::fromLParam(::GetMessagePos());
+			if(tooltip) {
+				// don't cover the parent when showing as a tooltip.
+				pt.y = parent->getWindowRect().bottom() + margin;
+			}
 		}
 
-		// create the popup container (invisible at first)
-		Seed cs(WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE);
-		cs.location = dwt::Rectangle(pt, dwt::Point()); // set the position but not the size
-		create(cs);
-		onLeftMouseDown([this](const dwt::MouseEvent&) { return close(); });
-		onKeyDown([this](int) { return close(); });
-		onHelp([this](Widget*, unsigned) { handleHelp(); });
-
-		// create the inner text control
-		ts = WinUtil::Seeds::richTextBox;
-		ts.style = WS_CHILD | WS_VISIBLE | ES_READONLY;
-		ts.exStyle = 0;
-		ts.location = dwt::Rectangle(margins, dwt::Point(maxWidth, 0));
-		createBox();
+		// create the box as an invisible popup window.
+		auto seed = WinUtil::Seeds::richTextBox;
+		seed.style = WS_POPUP | ES_READONLY;
+		if(multiline)
+			seed.style |= ES_MULTILINE;
+		seed.exStyle = WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_CLIENTEDGE;
+		seed.location.size.x = std::min(getDesktopSize().x, static_cast<long>(maxWidth * dwt::util::dpiFactor()));
+		create(seed);
+
+		const auto margins = sendMessage(EM_GETMARGINS);
+		sendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(LOWORD(margins) + margin, HIWORD(margins) + margin));
+
+		// let the control figure out what the best size is.
+		onRaw([this, pt](WPARAM, LPARAM l) { return this->resize(l, pt); }, dwt::Message(WM_NOTIFY, EN_REQUESTRESIZE));
+		sendMessage(EM_SETEVENTMASK, 0, ENM_REQUESTRESIZE); ///@todo move to dwt
+		setText(text);
 	}
 
 private:
-	void createBox() {
-		box = addChild(ts);
-		box->setColor(dwt::Color::predefined(COLOR_INFOTEXT), dwt::Color::predefined(COLOR_INFOBK));
-
-		// let the control figure out what the best size is
-		box->onRaw([this](WPARAM, LPARAM l) { return resize(l); }, dwt::Message(WM_NOTIFY, EN_REQUESTRESIZE));
-		box->sendMessage(EM_SETEVENTMASK, 0, ENM_REQUESTRESIZE); ///@todo move to dwt
-		box->setText(text);
-	}
-
-	void multilineBox() {
-		// can't add ES_MULTILINE at run time, so we create the control again
-		::DestroyWindow(box->handle());
-		ts.style |= ES_MULTILINE;
-		createBox();
-	}
-
-	LRESULT resize(LPARAM lParam) {
-		{
-			dwt::Rectangle rect(reinterpret_cast<REQRESIZE*> (lParam)->rc);
-			if(rect.width() > maxWidth && (ts.style & ES_MULTILINE) != ES_MULTILINE) {
-				callAsync([this] { multilineBox(); });
-				return 0;
-			}
-
-			box->resize(rect);
+	LRESULT resize(LPARAM lParam, const dwt::Point& pos) {
+		if(getVisible())
+			return 0;
+
+		dwt::Rectangle rect(reinterpret_cast<REQRESIZE*>(lParam)->rc);
+
+		if(rect.width() > getWindowRect().width() && !hasStyle(ES_MULTILINE)) {
+			// can't add ES_MULTILINE at run time, so create the control again.
+			new ThisType(getParent(), text, timeout, true);
+			close();
+			return 0;
 		}
 
-		// now that the text control is correctly sized, resize the container window
-		dwt::Rectangle rect = box->getWindowRect();
-		rect.pos -= margins;
-		rect.size += margins + margins;
+		rect.pos = pos;
 		rect.size.x += ::GetSystemMetrics(SM_CXEDGE) * 2;
-		rect.size.y += ::GetSystemMetrics(SM_CYEDGE) * 2;
+		rect.size.y += ::GetSystemMetrics(SM_CYEDGE) * 2 + margin;
 
 		// make sure the window fits in within the screen
-		dwt::Point pt = getDesktopSize();
-		if(rect.right() > pt.x)
-			rect.pos.x -= rect.size.x;
-		if(rect.bottom() > pt.y)
-			rect.pos.y -= rect.size.y;
-
-		BaseType::resize(rect);
+		const auto screen = getDesktopSize();
+		if(rect.right() > screen.x) { rect.pos.x -= rect.right() - screen.x; }
+		if(rect.left() < 0) { rect.pos.x = 0; }
+		if(!tooltip && rect.bottom() > screen.y) { rect.pos.y -= rect.bottom() - screen.y; }
+		if(!tooltip && rect.top() < 0) { rect.pos.y = 0; }
+
+		setColor(dwt::Color::predefined(COLOR_INFOTEXT), dwt::Color::predefined(COLOR_INFOBK));
+
+		if(tooltip) {
+			setTimer([this] { return !this->close(); }, timeout);
+
+		} else {
+			// capture the mouse.
+			onLeftMouseDown([this](const dwt::MouseEvent&) { return this->close(); });
+			::SetCapture(handle());
+			onDestroy([] { ::ReleaseCapture(); });
+
+			// capture the keyboard.
+			auto focus = dwt::hwnd_cast<dwt::Widget*>(::GetFocus());
+			if(focus) {
+				auto cb1 = focus->addCallback(dwt::Message(WM_KEYDOWN), [this](const MSG&, LRESULT&) { return this->close(); });
+				auto cb2 = focus->addCallback(dwt::Message(WM_HELP), [this](const MSG&, LRESULT&) { return this->close(); });
+				onDestroy([this, focus, cb1, cb2] {
+					auto cb1_ = cb1; focus->clearCallback(dwt::Message(WM_KEYDOWN), cb1_);
+					auto cb2_ = cb2; focus->clearCallback(dwt::Message(WM_KEYDOWN), cb2_);
+				});
+			}
+		}
 
 		// go live!
-		setVisible(true);
-		::SetCapture(handle());
+		::SetWindowPos(handle(), 0, rect.left(), rect.top(), rect.width(), rect.height(),
+			SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_SHOWWINDOW);
 
 		return 0;
 	}
 
 	bool close() {
-		::ReleaseCapture();
 		BaseType::close(true);
 		return true;
 	}
 
-	void handleHelp() {
-		// someone pressed F1 while the popup was shown... do nothing.
-	}
-
-	static const dwt::Point margins;
+	static const long margin = 6;
 	static const long maxWidth = 400;
 
-	RichTextBoxPtr box;
-	RichTextBox::Seed ts;
-	tstring text;
+	const tstring text;
+	unsigned timeout;
 };
-const dwt::Point HelpPopup::margins(6, 6);
 
 void WinUtil::help(dwt::Control* widget, unsigned id) {
 	if(id >= IDH_CSHELP_BEGIN && id <= IDH_CSHELP_END) {
 		// context-sensitive help
-		new HelpPopup(widget, Text::toT(getHelpText(id)));
+		new HelpPopup<false>(widget, Text::toT(getHelpText(id)));
 	} else {
 #ifdef HAVE_HTMLHELP_H
 		if(id < IDH_BEGIN || id > IDH_END)
@@ -1009,6 +1012,14 @@
 	}
 }
 
+void WinUtil::helpTooltip(dwt::Control* widget, unsigned timeout) {
+	auto id = widget->getHelpId();
+	if(id >= IDH_CSHELP_BEGIN && id <= IDH_CSHELP_END) {
+		// context-sensitive help
+		new HelpPopup<true>(widget, Text::toT(getHelpText(id)), timeout);
+	}
+}
+
 string WinUtil::getHelpText(unsigned id) {
 	if(id >= IDH_CSHELP_BEGIN) {
 		id -= IDH_CSHELP_BEGIN;

=== modified file 'win32/WinUtil.h'
--- win32/WinUtil.h	2012-01-07 20:25:42 +0000
+++ win32/WinUtil.h	2012-01-11 21:42:27 +0000
@@ -288,6 +288,7 @@
 	static void parseMagnetUri(const tstring& /*aUrl*/, bool aOverride = false);
 
 	static void help(dwt::Control* widget, unsigned id);
+	static void helpTooltip(dwt::Control* widget, unsigned timeout);
 	static string getHelpText(unsigned id);
 
 	// URL related

=== modified file 'win32/forward.h'
--- win32/forward.h	2011-12-26 16:12:50 +0000
+++ win32/forward.h	2012-01-11 21:42:27 +0000
@@ -40,6 +40,7 @@
 using dwt::TextBoxPtr;
 using dwt::TreePtr;
 using dwt::ToolBarPtr;
+using dwt::ToolTipPtr;
 
 class ComboBox;
 typedef ComboBox* ComboBoxPtr;

=== modified file 'win32/main.cpp'
--- win32/main.cpp	2011-06-28 20:07:49 +0000
+++ win32/main.cpp	2012-01-11 21:42:27 +0000
@@ -26,10 +26,6 @@
 #include "MainWindow.h"
 #include "SplashWindow.h"
 
-#include "Mapper_NATPMP.h"
-#include "Mapper_MiniUPnPc.h"
-#include "Mapper_WinUPnP.h"
-
 #include <dcpp/MerkleTree.h>
 #include <dcpp/File.h>
 #include <dcpp/Text.h>
@@ -153,10 +149,6 @@
 			SetProcessDefaultLayout(LAYOUT_RTL);
 		}
 
-		MappingManager::getInstance()->addMapper<Mapper_NATPMP>();
-		MappingManager::getInstance()->addMapper<Mapper_MiniUPnPc>();
-		MappingManager::getInstance()->addMapper<Mapper_WinUPnP>();
-
 		WinUtil::init();
 
 		MainWindow* wnd = new MainWindow;