diff --git a/applications/gui2/src/views/addsource.cpp b/applications/gui2/src/views/addsource.cpp
index e698d2dcdf85170da60e670c820778f1e14e1c36..91b9041aec3f356ebe226873454b004f8c446725 100644
--- a/applications/gui2/src/views/addsource.cpp
+++ b/applications/gui2/src/views/addsource.cpp
@@ -34,12 +34,75 @@ AddSourceWindow::AddSourceWindow(nanogui::Widget* parent, AddCtrl *ctrl) :
 	close->setBackgroundColor(theme()->mWindowHeaderGradientBot);
 	close->setCallback([this](){ this->close();});
 
+	auto *title = new Label(this, "Add Source", "sans-bold");
+	title->setFontSize(28);
+
+	tabs_ = new TabWidget(this);
+
+	auto *recent_tab = tabs_->createTab("Recent");
+	recent_tab->setLayout(new nanogui::BoxLayout
+				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
+	VScrollPanel *vscroll = new VScrollPanel(recent_tab);
+	vscroll->setFixedHeight(200);
+	Widget *recentscroll = new Widget(vscroll);
+	recentscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
+
+	auto *group_tab = tabs_->createTab("Groups");
+	group_tab->setLayout(new nanogui::BoxLayout
+				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
+	vscroll = new VScrollPanel(group_tab);
+	vscroll->setFixedHeight(200);
+	Widget *groupscroll = new Widget(vscroll);
+	groupscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
+
+	auto *dev_tab = tabs_->createTab("Devices");
+	dev_tab->setLayout(new nanogui::BoxLayout
+				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
+	vscroll = new VScrollPanel(dev_tab);
+	vscroll->setFixedHeight(200);
+	Widget *devscroll = new Widget(vscroll);
+	devscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
+
+	auto *host_tab = tabs_->createTab("Hosts");
+	host_tab->setLayout(new nanogui::BoxLayout
+				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
+	vscroll = new VScrollPanel(host_tab);
+	vscroll->setFixedHeight(200);
+	Widget *hostscroll = new Widget(vscroll);
+	hostscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
+
+	auto *stream_tab = tabs_->createTab("Streams");
+	stream_tab->setLayout(new nanogui::BoxLayout
+				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
+	vscroll = new VScrollPanel(stream_tab);
+	vscroll->setFixedHeight(200);
+	Widget *streamscroll = new Widget(vscroll);
+	streamscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
+
+	auto *file_tab = tabs_->createTab("Files");
+	file_tab->setLayout(new nanogui::BoxLayout
+				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
+	vscroll = new VScrollPanel(file_tab);
+	vscroll->setFixedHeight(200);
+	Widget *filescroll = new Widget(vscroll);
+	filescroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
+
+	tab_items_.resize(6);
+	tab_items_[0] = recentscroll;
+	tab_items_[1] = groupscroll;
+	tab_items_[2] = devscroll;
+	tab_items_[3] = hostscroll;
+	tab_items_[4] = streamscroll;
+	tab_items_[5] = filescroll;
+
+	uptodate_.test_and_set();
 	rebuild();
+	tabs_->setActiveTab(0);
 
 	new_source_handle_ = ctrl_->feed()->onNewSources([this](int a) {
 		LOG(INFO) << "NEW SOURCES";
 		UNIQUE_LOCK(mutex_, lk);
-		do_rebuild_ = true;
+		uptodate_.clear();
 		return true;
 	});
 }
@@ -83,65 +146,29 @@ nanogui::Button *AddSourceWindow::_addButton(const std::string &s, nanogui::Widg
 
 void AddSourceWindow::rebuild() {
 	using namespace nanogui;
-	
-	auto *title = new Label(this, "Add Source", "sans-bold");
-	title->setFontSize(28);
-
-	auto *tabs = new TabWidget(this);
-
-	auto *recent_tab = tabs->createTab("Recent");
-	recent_tab->setLayout(new nanogui::BoxLayout
-				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
-	VScrollPanel *vscroll = new VScrollPanel(recent_tab);
-	vscroll->setFixedHeight(200);
-	Widget *recentscroll = new Widget(vscroll);
-	recentscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
 
+	for (auto *w : tab_items_) {
+		while (w->childCount() > 0) w->removeChild(w->childCount()-1);
+	}
+	
 	Button *button;
 
 	auto srcs = ctrl_->getRecent();
-
 	for (auto &s : srcs) {
-		_addButton(s.uri, recentscroll);
+		_addButton(s.uri, tab_items_[0]);
 	}
 
-	auto *group_tab = tabs->createTab("Groups");
-	group_tab->setLayout(new nanogui::BoxLayout
-				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
-	vscroll = new VScrollPanel(group_tab);
-	vscroll->setFixedHeight(150);
-	Widget *groupscroll = new Widget(vscroll);
-	groupscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
-
 	auto groups = ctrl_->getGroups();
-
 	for (auto &s : groups) {
-		_addButton(s, groupscroll);
+		_addButton(s, tab_items_[1]);
 	}
 
-	auto *dev_tab = tabs->createTab("Devices");
-	dev_tab->setLayout(new nanogui::BoxLayout
-				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
-	vscroll = new VScrollPanel(dev_tab);
-	vscroll->setFixedHeight(150);
-	Widget *devscroll = new Widget(vscroll);
-	devscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
-
 	auto devsrcs = ctrl_->getDeviceSources();
-
 	for (auto &s : devsrcs) {
-		_addButton(s, devscroll);
+		_addButton(s, tab_items_[2]);
 	}
 
-	auto *host_tab = tabs->createTab("Hosts");
-	host_tab->setLayout(new nanogui::BoxLayout
-				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
-	vscroll = new VScrollPanel(host_tab);
-	vscroll->setFixedHeight(150);
-	Widget *hostscroll = new Widget(vscroll);
-	hostscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
-
-	button = new Button(hostscroll, "Add Host", ENTYPO_ICON_PLUS);
+	button = new Button(tab_items_[3], "Add Host", ENTYPO_ICON_PLUS);
 	button->setIconPosition(Button::IconPosition::Left);
 	button->setIconExtraScale(1.2);
 	button->setFontSize(18);
@@ -151,36 +178,19 @@ void AddSourceWindow::rebuild() {
 	});
 
 	auto hostsrcs = ctrl_->getHosts();
-
 	for (auto &s : hostsrcs) {
-		_addButton(s, hostscroll);
+		_addButton(s, tab_items_[3]);
 	}
 
-	auto *stream_tab = tabs->createTab("Streams");
-	stream_tab->setLayout(new nanogui::BoxLayout
-				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
-	vscroll = new VScrollPanel(stream_tab);
-	vscroll->setFixedHeight(150);
-	Widget *streamscroll = new Widget(vscroll);
-	streamscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
-
 	auto streamsrcs = ctrl_->getNetSources();
-
 	for (auto &s : streamsrcs) {
-		_addButton(s, streamscroll);
+		_addButton(s, tab_items_[4]);
 	}
 
-	auto *file_tab = tabs->createTab("Files");
-	file_tab->setLayout(new nanogui::BoxLayout
-				(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0));
-	vscroll = new VScrollPanel(file_tab);
-	vscroll->setFixedHeight(150);
-	Widget *filescroll = new Widget(vscroll);
-	filescroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4));
+	auto *file_menu = new Widget(tab_items_[5]);
+	file_menu->setLayout(new BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Maximum, 5,4));
 
-	button = new Button(filescroll, "Open", ENTYPO_ICON_PLUS);
-	button->setIconPosition(Button::IconPosition::Left);
-	button->setIconExtraScale(1.2);
+	button = new Button(file_menu, "Open", ENTYPO_ICON_PLUS);
 	button->setFontSize(18);
 	button->setTooltip("Open FTL File");
 	button->setCallback([this]() {
@@ -205,64 +215,18 @@ void AddSourceWindow::rebuild() {
 		close();
 	});
 
-	auto filesrcs = ctrl_->getFileSources();
+	button = new Button(file_menu, "Clear", ENTYPO_ICON_CYCLE);
+	button->setFontSize(18);
+	button->setTooltip("Clear file history");
+	button->setCallback([this]() {
+		ctrl_->feed()->clearFileHistory();
+		uptodate_.clear();
+	});
 
+	auto filesrcs = ctrl_->getFileSources();
 	for (auto &s : filesrcs) {
-		_addButton(s, filescroll);
+		_addButton(s, tab_items_[5]);
 	}
-
-
-	tabs->setActiveTab(0);
-
-
-	/*button = new Button(devicebuttons, "Camera(s)");
-	button->setCallback([this]() { ctrl_->add("device:camera"); close(); });
-	button = new Button(devicebuttons, "Realsense");
-	button->setCallback([this]() { ctrl_->add("device:realsense"); close(); });
-	button = new Button(devicebuttons, "Screen");
-	button->setCallback([this]() { ctrl_->add("device:screen"); close(); });
-	button = new Button(devicebuttons, "3D Camera");
-	button->setCallback([this]() { ctrl_->add("device:render"); close(); });
-	button = new Button(devicebuttons, "OpenVR");
-	button->setCallback([this]() { ctrl_->add("device:openvr"); close(); });*/
-
-	/*new Label(this, "Network Sources", "sans-bold");
-
-	auto *netbuttons = new Widget(this);
-	netbuttons->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 4));
-	auto netsrcs = ctrl_->getNetSources();
-
-	for (auto &s : netsrcs) {
-		button = new Button(netbuttons, ctrl_->getSourceName(s));
-		if (ctrl_->isSourceActive(s)) {
-			button->setBackgroundColor(Color(0, 255, 0, 25));
-		}
-
-		button->setCallback([this, s]() {
-			ctrl_->add(s);
-			close();
-		});
-	}*/
-
-	//new Label(this, "Files", "sans-bold");
-
-	//auto *filebuttons = new Widget(this);
-	//filebuttons->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 4));
-	
-
-	/*auto filesrcs = ctrl_->getFileSources();
-
-	for (auto &s : filesrcs) {
-		button = new Button(filebuttons, ctrl_->getSourceName(s));
-		if (ctrl_->isSourceActive(s)) {
-			button->setBackgroundColor(Color(0, 255, 0, 25));
-		}
-
-		button->setCallback([this, s]() {
-			ctrl_->add(s);
-			close();
-		});
-	}*/
 }
 
 void AddSourceWindow::close() {
@@ -274,10 +238,10 @@ void AddSourceWindow::close() {
 void AddSourceWindow::draw(NVGcontext *ctx) {
 	{
 		UNIQUE_LOCK(mutex_, lk);
-		if (do_rebuild_) {
-			do_rebuild_ = false;
+		if (!uptodate_.test_and_set()) {
+			tabs_->requestFocus();
 			// Note the 1, first widget is the title bar buttons
-			while(childCount() > 1) { removeChild(childCount()-1); }
+			//while(childCount() > 1) { removeChild(childCount()-1); }
 			rebuild();
 			screen()->performLayout();
 		}
diff --git a/applications/gui2/src/views/addsource.hpp b/applications/gui2/src/views/addsource.hpp
index 938e1e3dde73d87b484814d8b98f731394045a0f..da075fbab3fc4ac93cc4aee96f70c3301b20c69a 100644
--- a/applications/gui2/src/views/addsource.hpp
+++ b/applications/gui2/src/views/addsource.hpp
@@ -29,7 +29,9 @@ private:
 
 	ftl::Handle new_source_handle_;
 	MUTEX mutex_;
-	std::atomic_bool do_rebuild_=false;
+	std::atomic_flag uptodate_;
+	std::vector<nanogui::Widget*> tab_items_;
+	nanogui::TabWidget *tabs_;
 
 public:
 	// EIGEN_MAKE_ALIGNED_OPERATOR_NEW
diff --git a/components/streams/include/ftl/streams/feed.hpp b/components/streams/include/ftl/streams/feed.hpp
index c8565fcf209ab54148180d584a6d850f2f447303..5cfddc7071acd25c2795bebe0f8bf8a62d573640 100644
--- a/components/streams/include/ftl/streams/feed.hpp
+++ b/components/streams/include/ftl/streams/feed.hpp
@@ -111,6 +111,8 @@ public:
 	bool sourceAvailable(const std::string &uri);
 	bool sourceActive(const std::string &uri);
 
+	void clearFileHistory();
+
 	/**
 	 * Perform a render tick for all render sources. Note that this must be
 	 * called from the GUI / OpenGL thread.
diff --git a/components/streams/src/feed.cpp b/components/streams/src/feed.cpp
index 0a6fb2da8b41d68cc719ac6581669de1372f97ab..6d149d13189b48a55d0868127154db9c713862da 100644
--- a/components/streams/src/feed.cpp
+++ b/components/streams/src/feed.cpp
@@ -568,6 +568,22 @@ std::vector<std::string> Feed::availableFileSources() {
 	return files;
 }
 
+void Feed::clearFileHistory() {
+	UNIQUE_LOCK(mtx_, lk);
+	auto &recent_files = getConfig()["recent_files"];
+	recent_files.clear();
+
+	auto &recent = getConfig()["recent_sources"];
+	for (auto i=recent.begin(); i != recent.end();) {
+		ftl::URI uri(i.key());
+		if (uri.getScheme() == ftl::URI::SCHEME_FILE) {
+			i = recent.erase(i);
+		} else {
+			++i;
+		}
+	}
+}
+
 std::vector<std::string> Feed::knownHosts() {
 	std::vector<std::string> hosts;
 	auto &known = getConfig()["known_hosts"];
@@ -680,7 +696,13 @@ std::string Feed::getName(const std::string &puri) {
 		if (uri.getPathSegment(0) == "openvr") return "OpenVR";
 		return "Unknown Device";
 	} else if (uri.getScheme() == ftl::URI::SCHEME_FILE) {
-		return getConfig()["recent_files"][uri.getBaseURI()].value("name", "FTLFile");
+		auto &recent_files = getConfig()["recent_files"];
+		if (recent_files.is_structured() && recent_files.contains(uri.getBaseURI())) {
+			return recent_files[uri.getBaseURI()].value("name", uri.getPathSegment(-1));
+		} else {
+			LOG(INFO) << "Missing file: " << puri;
+			return uri.getPathSegment(-1);
+		}
 	} else if (uri.getScheme() == ftl::URI::SCHEME_TCP || uri.getScheme() == ftl::URI::SCHEME_WS) {
 		return uri.getBaseURI();
 	} else if (uri.getScheme() == ftl::URI::SCHEME_GROUP) {