← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3073: destroy tooltips, reduce CPU use due to status updates

 

------------------------------------------------------------
revno: 3073
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Thu 2012-10-11 18:17:05 +0200
message:
  destroy tooltips, reduce CPU use due to status updates
modified:
  changelog.txt
  dcpp/TaskQueue.h
  dwt/include/dwt/resources/Handle.h
  dwt/include/dwt/widgets/Button.h
  dwt/include/dwt/widgets/ToolTip.h
  dwt/src/widgets/Button.cpp
  dwt/src/widgets/Splitter.cpp
  dwt/src/widgets/StatusBar.cpp
  win32/DirectoryListingFrame.cpp
  win32/DirectoryListingFrame.h
  win32/QueueFrame.cpp
  win32/QueueFrame.h
  win32/RichTextBox.cpp
  win32/UsersFrame.cpp
  win32/UsersFrame.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 'changelog.txt'
--- changelog.txt	2012-10-04 19:57:25 +0000
+++ changelog.txt	2012-10-11 16:17:05 +0000
@@ -1,7 +1,8 @@
 * Perf improvements using lock-free queues, requires P6 CPUs (poy)
 * Reduce freezes when displaying file list dirs that contain lots of files (poy)
-* Less CPU consumption in large hubs (poy)
+* Less CPU consumption with large hubs/queues/lists (poy)
 * Fix incorrect user lists when DC++ is under heavy load (poy)
+* Plug resource leaks (poy)
 
 -- 0.801 2012-09-29 --
 * [L#1029629] Prevent crashes on heavy use by updating Boost.Atomic

=== modified file 'dcpp/TaskQueue.h'
--- dcpp/TaskQueue.h	2012-10-04 19:31:21 +0000
+++ dcpp/TaskQueue.h	2012-10-11 16:17:05 +0000
@@ -47,10 +47,6 @@
 	typedef vector<pair<int, unique_ptr<Task>>> List;
 
 public:
-	virtual ~TaskQueue() {
-		clear();
-	}
-
 	void add(int type, std::unique_ptr<Task> && data) { tasks.emplace_back(type, move(data)); }
 	List get() { return move(tasks); }
 	void clear() { tasks.clear(); }

=== modified file 'dwt/include/dwt/resources/Handle.h'
--- dwt/include/dwt/resources/Handle.h	2012-05-13 11:48:45 +0000
+++ dwt/include/dwt/resources/Handle.h	2012-10-11 16:17:05 +0000
@@ -56,17 +56,11 @@
 template<typename Policy>
 class Handle;
 
-template<typename Policy>
-void intrusive_ptr_add_ref(Handle<Policy>* resource);
-
-template<typename Policy>
-void intrusive_ptr_release(Handle<Policy>* resource);
-
 /**
  * Ref-counted base class for resources - nothing stops you from using this one the stack as well
  */
 template<typename Policy>
-class Handle : protected Policy, public boost::noncopyable {
+class Handle : protected Policy, boost::noncopyable {
 public:
 	typedef typename Policy::HandleType HandleType;
 
@@ -88,8 +82,8 @@
 	}
 
 private:
-	friend void intrusive_ptr_add_ref<Policy>(Handle<Policy>*);
-	friend void intrusive_ptr_release<Policy>(Handle<Policy>*);
+	friend void intrusive_ptr_add_ref(Handle<Policy>* p) { ++p->ref; }
+	friend void intrusive_ptr_release(Handle<Policy>* p) { if(--p->ref == 0) { delete p; } }
 
 	HandleType h;
 	bool owned;
@@ -97,17 +91,6 @@
 	long ref;
 };
 
-template<typename Policy>
-void intrusive_ptr_add_ref(Handle<Policy>* resource) {
-	::InterlockedIncrement(&resource->ref);
-}
-
-template<typename Policy>
-void intrusive_ptr_release(Handle<Policy>* resource) {
-	if(::InterlockedDecrement(&resource->ref) == 0) {
-		delete resource;
-	}
-}
-
-}
+}
+
 #endif /*RESOURCE_H_*/

=== modified file 'dwt/include/dwt/widgets/Button.h'
--- dwt/include/dwt/widgets/Button.h	2012-01-13 20:55:20 +0000
+++ dwt/include/dwt/widgets/Button.h	2012-10-11 16:17:05 +0000
@@ -108,11 +108,6 @@
 	return Message(WM_COMMAND, MAKEWPARAM(0, BN_DBLCLK));
 }
 
-inline Button::Button(Widget* parent) :
-	BaseType(parent, ChainingDispatcher::superClass<ThisType>())
-{
-}
-
 }
 
 #endif /*ASPECTBUTTON_H_*/

=== modified file 'dwt/include/dwt/widgets/ToolTip.h'
--- dwt/include/dwt/widgets/ToolTip.h	2012-06-02 12:48:00 +0000
+++ dwt/include/dwt/widgets/ToolTip.h	2012-10-11 16:17:05 +0000
@@ -33,6 +33,7 @@
 #define DWT_ToolTip_H_
 
 #include "../Widget.h"
+#include "../aspects/Closeable.h"
 #include "../aspects/CustomDraw.h"
 #include "../aspects/Enabled.h"
 #include "../aspects/Fonts.h"
@@ -44,6 +45,7 @@
 
 class ToolTip :
 	public Widget,
+	public aspects::Closeable<ToolTip>,
 	public aspects::CustomDraw<ToolTip, NMTTCUSTOMDRAW>,
 	public aspects::Enabled<ToolTip>,
 	public aspects::Fonts<ToolTip>,
@@ -87,12 +89,12 @@
 
 	void onGetTip(F f);
 
-	/// Actually creates the Toolbar
-	/** You should call WidgetFactory::createToolbar if you instantiate class
-	  * directly. <br>
-	  * Only if you DERIVE from class you should call this function directly.
-	  */
-	void create( const Seed & cs = Seed() );
+	/** Create the ToolTip control.
+	@note Be careful about tooltip destruction! Unlike other widgets, tooltips aren't regular
+	children; they are instead "owned" by their parent (Windows terminology). Therefore, unless the
+	owner doesn't have any non-owner parent, Windows won't destroy the tooltip control when the
+	owner is destroyed; so make sure you explicitly destroy it by calling the "close" method. */
+	void create(const Seed& cs = Seed());
 
 protected:
 	// Constructor Taking pointer to parent

=== modified file 'dwt/src/widgets/Button.cpp'
--- dwt/src/widgets/Button.cpp	2012-01-13 20:55:20 +0000
+++ dwt/src/widgets/Button.cpp	2012-10-11 16:17:05 +0000
@@ -44,6 +44,11 @@
 {
 }
 
+Button::Button(Widget* parent) :
+	BaseType(parent, ChainingDispatcher::superClass<ThisType>())
+{
+}
+
 void Button::create(const Seed& cs) {
 	BaseType::create(cs);
 	setFont(cs.font);
@@ -62,14 +67,8 @@
 
 Point Button::getPreferredSize() {
 	SIZE size = { 0 };
-	if(sendMessage(BCM_GETIDEALSIZE, 0, reinterpret_cast<LPARAM>(&size))) {
-		return Point(size.cx, size.cy);
-	}
-
-	// BCM_GETIDEALSIZE fails on comctrl < 6, so resort to the standard method
-	UpdateCanvas c(this);
-	auto select(c.select(*getFont()));
-	return c.getTextExtent(getText()) + Point(3, 2) + Point(::GetSystemMetrics(SM_CYFIXEDFRAME) * 2, ::GetSystemMetrics(SM_CXFIXEDFRAME) * 2);
+	sendMessage(BCM_GETIDEALSIZE, 0, reinterpret_cast<LPARAM>(&size));
+	return Point(size.cx, size.cy);
 }
 
 }

=== modified file 'dwt/src/widgets/Splitter.cpp'
--- dwt/src/widgets/Splitter.cpp	2012-06-29 19:22:25 +0000
+++ dwt/src/widgets/Splitter.cpp	2012-10-11 16:17:05 +0000
@@ -53,7 +53,9 @@
 	onMouseMove([this](const MouseEvent& mouseEvent) { return handleMouseMove(mouseEvent); });
 	onLeftMouseUp([this](const MouseEvent&) { return handleLButtonUp(); });
 
-	WidgetCreator<ToolTip>::create(this, ToolTip::Seed())->setText(Texts::get(Texts::resize));
+	auto tip = WidgetCreator<ToolTip>::create(this, ToolTip::Seed());
+	tip->setText(Texts::get(Texts::resize));
+	onDestroy([tip] { tip->close(); });
 }
 
 SplitterContainerPtr Splitter::getParent() const {

=== modified file 'dwt/src/widgets/StatusBar.cpp'
--- dwt/src/widgets/StatusBar.cpp	2012-03-03 19:33:45 +0000
+++ dwt/src/widgets/StatusBar.cpp	2012-10-11 16:17:05 +0000
@@ -70,6 +70,7 @@
 
 	tip = WidgetCreator<ToolTip>::create(this, ToolTip::Seed());
 	tip->setTool(this, [this](tstring& text) { handleToolTip(text); });
+	onDestroy([this] { tip->close(); tip = nullptr; });
 }
 
 void StatusBar::setSize(unsigned part, unsigned size) {

=== modified file 'win32/DirectoryListingFrame.cpp'
--- win32/DirectoryListingFrame.cpp	2012-10-04 19:31:21 +0000
+++ win32/DirectoryListingFrame.cpp	2012-10-11 16:17:05 +0000
@@ -224,6 +224,7 @@
 	BaseType(parent, _T(""), IDH_FILE_LIST, IDI_DIRECTORY, false),
 	loader(nullptr),
 	loading(0),
+	useCache(true),
 	rebar(0),
 	pathBox(0),
 	grid(0),
@@ -425,7 +426,7 @@
 	}
 
 #ifdef _DEBUG
-#define step(x) dcdebug("Loading file list <%s>: " x "\n", parent.path.c_str());
+#define step(x) dcdebug("Loading file list <%s>: " x "\n", parent.path.c_str())
 #else
 #define step(x)
 #endif
@@ -452,16 +453,16 @@
 			successF();
 
 		} catch(const Exception& e) {
-			step("error")
+			step("error");
 			errorF(Text::toT(e.getError()));
 		}
 
 		/* now that the file list is being displayed, prepare individual file items, hoping that
 		they will have been processed by the time the user wants them to be displayed. */
-		try {
+		if(parent.useCache) { try {
 			step("caching files");
 			cacheFiles(parent.dl->getRoot());
-		} catch(const Exception&) { }
+		} catch(const Exception&) { } }
 
 		step("file cache done; destroying thread");
 		endF();
@@ -1257,27 +1258,34 @@
 
 void DirectoryListingFrame::changeDir(DirectoryListing::Directory* d) {
 	updating = true;
+	if(!useCache) { files->forEachT([](ItemInfo* i) { if(i->type == ItemInfo::FILE) { delete i; } }); } /// @todo also delete when closing the window
 	files->clear();
 
-	auto cache = fileCache.find(d);
-	if(cache == fileCache.end()) {
-		if(!loader || !loader->updateCache(d)) {
-			/* dang, the file cache isn't ready for this directory. fill it on-the-fly; might
-			freeze the interface (this is the operation the file cache is meant to prevent). */
-			list<ItemInfo> list;
-			for(auto& i: d->files) {
-				list.emplace_back(i);
-			}
-			fileCache.emplace(d, move(list));
-		}
-		cache = fileCache.find(d);
-	}
-
 	for(auto& i: d->directories) {
 		files->insert(files->size(), getCachedDir(i));
 	}
-	for(auto& i: cache->second) {
-		files->insert(files->size(), &i);
+
+	if(useCache) {
+		auto cache = fileCache.find(d);
+		if(cache == fileCache.end()) {
+			if(!loader || !loader->updateCache(d)) {
+				/* dang, the file cache isn't ready for this directory. fill it on-the-fly; might
+				freeze the interface (this is the operation the file cache is meant to prevent). */
+				list<ItemInfo> list;
+				for(auto& i: d->files) {
+					list.emplace_back(i);
+				}
+				fileCache.emplace(d, move(list));
+			}
+			cache = fileCache.find(d);
+		}
+		for(auto& i: cache->second) {
+			files->insert(files->size(), &i);
+		}
+	} else {
+		for(auto& i: d->files) {
+			files->insert(files->size(), new ItemInfo(i));
+		}
 	}
 
 	files->resort();

=== modified file 'win32/DirectoryListingFrame.h'
--- win32/DirectoryListingFrame.h	2012-09-29 12:29:21 +0000
+++ win32/DirectoryListingFrame.h	2012-10-11 16:17:05 +0000
@@ -27,7 +27,6 @@
 #include <dcpp/forward.h>
 #include <dcpp/ClientManagerListener.h>
 #include <dcpp/DirectoryListing.h>
-#include <dcpp/FastAlloc.h>
 #include <dcpp/StringMatch.h>
 #include <dcpp/User.h>
 
@@ -103,7 +102,7 @@
 		COLUMN_LAST
 	};
 
-	class ItemInfo : public FastAlloc<ItemInfo> {
+	class ItemInfo {
 	public:
 		enum ItemType {
 			FILE,
@@ -167,6 +166,7 @@
 	LabelPtr loading;
 	unordered_map<DirectoryListing::Directory*, ItemInfo> dirCache;
 	unordered_map<DirectoryListing::Directory*, list<ItemInfo>> fileCache;
+	bool useCache;
 
 	RebarPtr rebar;
 	ComboBoxPtr pathBox;

=== modified file 'win32/QueueFrame.cpp'
--- win32/QueueFrame.cpp	2012-09-15 20:36:00 +0000
+++ win32/QueueFrame.cpp	2012-10-11 16:17:05 +0000
@@ -65,6 +65,7 @@
 dirs(0),
 files(0),
 dirty(true),
+filesDirty(true),
 usingDirMenu(false),
 queueSize(0),
 queueItems(0),
@@ -94,6 +95,7 @@
 
 		files->onKeyDown([this](int c) { return handleKeyDownFiles(c); });
 		files->onContextMenu([this](const dwt::ScreenCoordinate &sc) { return handleFilesContextMenu(sc); });
+		files->onSelectionChanged([this] { filesDirty = true; });
 
 		if(!SETTING(QUEUEFRAME_SHOW_TREE)) {
 			paned->maximize(files);
@@ -193,33 +195,38 @@
 }
 
 void QueueFrame::updateStatus() {
-	int64_t total = 0;
-	int cnt = files->countSelected();
-	if(cnt < 2) {
-		cnt = files->size();
-		if(SETTING(QUEUEFRAME_SHOW_TREE)) {
-			for(auto i = 0; i < cnt; ++i) {
+	if(filesDirty || dirty) {
+		filesDirty = false;
+
+		auto cnt = files->countSelected();
+		int64_t total = 0;
+		if(cnt < 2) {
+			cnt = files->size();
+			if(SETTING(QUEUEFRAME_SHOW_TREE)) {
+				for(decltype(cnt) i = 0; i < cnt; ++i) {
+					QueueItemInfo* ii = files->getData(i);
+					total += (ii->getSize() > 0) ? ii->getSize() : 0;
+				}
+			} else {
+				total = queueSize;
+			}
+		} else {
+			int i = -1;
+			while( (i = files->getNext(i, LVNI_SELECTED)) != -1) {
 				QueueItemInfo* ii = files->getData(i);
 				total += (ii->getSize() > 0) ? ii->getSize() : 0;
 			}
-		} else {
-			total = queueSize;
-		}
-	} else {
-		int i = -1;
-		while( (i = files->getNext(i, LVNI_SELECTED)) != -1) {
-			QueueItemInfo* ii = files->getData(i);
-			total += (ii->getSize() > 0) ? ii->getSize() : 0;
-		}
+		}
+
+		status->setText(STATUS_PARTIAL_COUNT, str(TF_("Items: %1%") % cnt));
+		status->setText(STATUS_PARTIAL_BYTES, str(TF_("Size: %1%") % Text::toT(Util::formatBytes(total))));
 	}
 
-	status->setText(STATUS_PARTIAL_COUNT, str(TF_("Items: %1%") % cnt));
-	status->setText(STATUS_PARTIAL_BYTES, str(TF_("Size: %1%") % Text::toT(Util::formatBytes(total))));
-
 	if(dirty) {
+		dirty = false;
+
 		status->setText(STATUS_TOTAL_COUNT, str(TF_("Files: %1%") % queueItems));
 		status->setText(STATUS_TOTAL_BYTES, str(TF_("Size: %1%") % Text::toT(Util::formatBytes(queueSize))));
-		dirty = false;
 	}
 }
 
@@ -288,6 +295,8 @@
 	files->resort();
 
 	curDir = getSelectedDir();
+
+	filesDirty = true;
 	updateStatus();
 }
 

=== modified file 'win32/QueueFrame.h'
--- win32/QueueFrame.h	2012-07-11 17:13:42 +0000
+++ win32/QueueFrame.h	2012-10-11 16:17:05 +0000
@@ -205,6 +205,8 @@
 	std::string curDir;
 
 	bool dirty;
+	bool filesDirty;
+
 	bool usingDirMenu;
 
 	int64_t queueSize;

=== modified file 'win32/RichTextBox.cpp'
--- win32/RichTextBox.cpp	2012-09-09 13:55:46 +0000
+++ win32/RichTextBox.cpp	2012-10-11 16:17:05 +0000
@@ -49,6 +49,7 @@
 	if((seed.events & ENM_LINK) == ENM_LINK) {
 		linkTip = dwt::WidgetCreator<dwt::ToolTip>::create(this, dwt::ToolTip::Seed());
 		linkTip->setTool(this, [this](tstring& text) { handleLinkTip(text); });
+		onDestroy([this] { linkTip->close(); linkTip = nullptr; });
 
 		onRaw([this](WPARAM, LPARAM lParam) { return handleLink(*reinterpret_cast<ENLINK*>(lParam)); },
 			dwt::Message(WM_NOTIFY, EN_LINK));

=== modified file 'win32/UsersFrame.cpp'
--- win32/UsersFrame.cpp	2012-09-10 22:14:27 +0000
+++ win32/UsersFrame.cpp	2012-10-11 16:17:05 +0000
@@ -111,7 +111,8 @@
 users(0),
 scroll(0),
 userInfo(0),
-filter(usersColumns, COLUMN_LAST, [this] { updateList(); })
+filter(usersColumns, COLUMN_LAST, [this] { updateList(); }),
+selected(-1)
 {
 	grid = addChild(Grid::Seed(2, 1));
 	grid->column(0).mode = GridInfo::FILL;
@@ -331,6 +332,11 @@
 }
 
 void UsersFrame::updateUserInfo() {
+	auto prevSelected = selected;
+	selected = users->countSelected() == 1 ? users->getSelected() : -1;
+	if(selected == prevSelected)
+		return;
+
 	ScopedFunctor([&] { scroll->layout(); userInfo->layout(); userInfo->redraw(); });
 
 	HoldRedraw hold(userInfo);
@@ -344,20 +350,17 @@
 	userInfo->clearRows();
 
 	if(users->countSelected() != 1) {
-		userInfo->redraw();
 		return;
 	}
 
 	auto sel = users->getSelectedData();
 	if(!sel) {
-		userInfo->redraw();
 		return;
 	}
 
 	auto user = sel->getUser();
 	auto idents = ClientManager::getInstance()->getIdentities(user);
 	if(idents.empty()) {
-		userInfo->redraw();
 		return;
 	}
 
@@ -427,7 +430,6 @@
 		if(dlg.run() == IDOK) {
 			FavoriteManager::getInstance()->setUserDescription(ui->getUser(), Text::fromT(dlg.getValue()));
 			ui->columns[COLUMN_DESCRIPTION] = dlg.getValue();
-			users->update(i);
 		}
 	}
 }

=== modified file 'win32/UsersFrame.h'
--- win32/UsersFrame.h	2012-09-10 22:14:27 +0000
+++ win32/UsersFrame.h	2012-10-11 16:17:05 +0000
@@ -127,6 +127,8 @@
 
 	ListFilter filter;
 
+	int selected;
+
 	static dwt::ImageListPtr userIcons;
 
 	std::unordered_map<UserPtr, UserInfo, User::Hash> userInfos;