← easystroke

Allow different timeout settings for individual devices

3f2c479bd2d6d746b3481e1ab47a00fc095a4b1b · Thomas Jaeger · Aug 9, 2011 21:47

+105 −49 · 5 files changed

  • main.cc +39 −2
  • prefdb.cc +2 −42
  • prefdb.h +4 −3
  • prefs.cc +50 −1
  • prefs.h +10 −1
diff --git a/main.cc b/main.cc
index 0adab57..be2a9f7 100644
--- a/main.cc
+++ b/main.cc
@@ -752,6 +752,36 @@ void Trace::end() {
 	end_();
 }
 
+static void get_timeouts(TimeoutType type, int *init, int *final) {
+	switch (type) {
+		case TimeoutOff:
+			*init = 0;
+			*final = 0;
+			break;
+		case TimeoutConservative:
+			*init = 750;
+			*final = 750;
+			break;
+		case TimeoutDefault:
+			*init = 250;
+			*final = 250;
+			break;
+		case TimeoutMedium:
+			*init = 100;
+			*final = 100;
+			break;
+		case TimeoutAggressive:
+			*init = 50;
+			*final = 75;
+			break;
+		case TimeoutFlick:
+			*init = 30;
+			*final = 50;
+			break;
+		default:;
+	}
+}
+
 class StrokeHandler : public Handler, public sigc::trackable {
 	guint button;
 	RPreStroke cur;
@@ -905,8 +935,15 @@ protected:
 	}
 public:
 	StrokeHandler(guint b, RTriple e) : button(b), is_gesture(false), drawing(false), last(e), orig(e),
-	use_timeout(prefs.init_timeout.get()),
-	init_timeout(prefs.init_timeout.get()), final_timeout(prefs.final_timeout.get()), radius(16) {}
+	init_timeout(prefs.init_timeout.get()), final_timeout(prefs.final_timeout.get()), radius(16) {
+		const std::map<std::string, TimeoutType> &dt = prefs.device_timeout.ref();
+		std::map<std::string, TimeoutType>::const_iterator j = dt.find(current_dev->name);
+		if (j != dt.end())
+			get_timeouts(j->second, &init_timeout, &final_timeout);
+		else
+			get_timeouts(prefs.timeout_profile.get(), &init_timeout, &final_timeout);
+		use_timeout = init_timeout;
+	}
 	virtual void init() {
 		if (grabber->is_instant(button))
 			return do_instant();
diff --git a/prefdb.cc b/prefdb.cc
index 358d405..cbcd76a 100644
--- a/prefdb.cc
+++ b/prefdb.cc
@@ -131,6 +131,8 @@ template<class Archive> void PrefDB::serialize(Archive & ar, const unsigned int
 	ar & show_osd.unsafe_ref();
 	if (version < 16) return;
 	ar & move_back.unsafe_ref();
+	if (version < 17) return;
+	ar & device_timeout.unsafe_ref();
 }
 
 void PrefDB::timeout() {
@@ -167,45 +169,6 @@ bool ButtonInfo::overlap(const ButtonInfo &bi) const {
 	return !((state ^ bi.state) & ~LockMask & ~Mod2Mask);
 }
 
-class TimeoutProfile : private Base {
-	Out<TimeoutType> &in;
-public:
-	virtual void notify() {
-		switch (in.get()) {
-			case TimeoutOff:
-				prefs.init_timeout.set(0);
-				prefs.final_timeout.set(0);
-				break;
-			case TimeoutConservative:
-				prefs.init_timeout.set(750);
-				prefs.final_timeout.set(750);
-				break;
-			case TimeoutDefault:
-				prefs.init_timeout.set(250);
-				prefs.final_timeout.set(250);
-				break;
-			case TimeoutMedium:
-				prefs.init_timeout.set(100);
-				prefs.final_timeout.set(100);
-				break;
-			case TimeoutAggressive:
-				prefs.init_timeout.set(50);
-				prefs.final_timeout.set(75);
-				break;
-			case TimeoutFlick:
-				prefs.init_timeout.set(30);
-				prefs.final_timeout.set(50);
-				break;
-			case TimeoutCustom:
-				break;
-		}
-	}
-	TimeoutProfile(Out<TimeoutType> &in_) : in(in_) {
-		in.connect(this);
-		notify();
-	}
-};
-
 void PrefDB::init() {
 	std::string filename = config_dir+"preferences";
 	for (const char **v = prefs_versions; *v; v++) {
@@ -231,9 +194,6 @@ void PrefDB::init() {
 		exceptions.unsafe_ref().erase(i);
 		exceptions.unsafe_ref()[""] = bi;
 	}
-	new TimeoutProfile(timeout_profile);
-	watch(init_timeout);
-	watch(final_timeout);
 }
 
 PrefDB prefs;
diff --git a/prefdb.h b/prefdb.h
index 942a53b..325fff4 100644
--- a/prefdb.h
+++ b/prefdb.h
@@ -119,8 +119,8 @@ public:
 	PrefSource<bool> proximity;
 	PrefSource<bool> feedback;
 	PrefSource<bool> left_handed;
-	Source<int> init_timeout;
-	Source<int> final_timeout;
+	PrefSource<int> init_timeout;
+	PrefSource<int> final_timeout;
 	PrefSource<TimeoutType> timeout_profile;
 	PrefSource<bool> timeout_gestures;
 	PrefSource<bool> tray_icon;
@@ -134,12 +134,13 @@ public:
 	PrefSource<bool> tray_feedback;
 	PrefSource<bool> show_osd;
 	PrefSource<bool> move_back;
+	PrefSource<std::map<std::string, TimeoutType> > device_timeout;
 
 	void init();
 	virtual void timeout();
 };
 
-BOOST_CLASS_VERSION(PrefDB, 16)
+BOOST_CLASS_VERSION(PrefDB, 17)
 
 extern PrefDB prefs;
 
diff --git a/prefs.cc b/prefs.cc
index 4916ec9..237ad3a 100644
--- a/prefs.cc
+++ b/prefs.cc
@@ -314,7 +314,30 @@ Prefs::Prefs() {
 	dtm = Gtk::ListStore::create(dcs);
 	dtv->set_model(dtm);
 	dtv->append_column_editable(_("Enabled"), dcs.enabled);
-	dtv->append_column(_("Device"), dcs.name);
+	int n = dtv->append_column(_("Device"), dcs.name);
+	Gtk::TreeView::Column *col_device = dtv->get_column(n-1);
+	col_device->set_expand();
+
+	Glib::RefPtr<Gtk::ListStore> timeout_model = Gtk::ListStore::create(timeout_columns);
+	{
+		Gtk::TreeModel::Row row = *(timeout_model->append());
+		row[timeout_columns.name] = _("<unchanged>");
+	}
+	for (const Combo<TimeoutType>::Info *i = timeout_info; i->name; i++) {
+		Gtk::TreeModel::Row row = *(timeout_model->append());
+		row[timeout_columns.name] = i->name;
+	}
+
+	Gtk::CellRendererCombo *timeout_renderer = Gtk::manage(new Gtk::CellRendererCombo);
+	timeout_renderer->property_model() = timeout_model;
+	timeout_renderer->property_editable() = true;
+	timeout_renderer->property_text_column() = 0;
+	timeout_renderer->property_has_entry() = false;
+        timeout_renderer->signal_edited().connect(sigc::mem_fun(*this, &Prefs::on_device_timeout_changed));
+	n = dtv->append_column(_("Timeout profile"), *timeout_renderer);
+	Gtk::TreeView::Column *col_timeout = dtv->get_column(n-1);
+	col_timeout->add_attribute(timeout_renderer->property_text(), dcs.timeout);
+
 	dtm->signal_row_changed().connect(sigc::mem_fun(*this, &Prefs::on_device_toggled));
 	update_device_list();
 
@@ -355,6 +378,14 @@ void Prefs::update_device_list() {
 		Gtk::TreeModel::Row row = *(dtm->append());
 		row[dcs.enabled] = !prefs.excluded_devices.get().count(name);
 		row[dcs.name] = name;
+		row[dcs.timeout] = _("<unchanged>");
+
+		const std::map<std::string, TimeoutType> &dt = prefs.device_timeout.ref();
+		std::map<std::string, TimeoutType>::const_iterator j = dt.find(name);
+		if (j != dt.end())
+			for (const Combo<TimeoutType>::Info *i = timeout_info; i->name; i++)
+				if (j->second == i->value)
+					row[dcs.timeout] = i->name;
 	}
 	ignore_device_toggled = false;
 }
@@ -645,6 +676,24 @@ void Prefs::on_device_toggled(const Gtk::TreeModel::Path& path, const Gtk::TreeM
 		ex.insert(device);
 }
 
+void Prefs::on_device_timeout_changed(const Glib::ustring& path, const Glib::ustring& new_text) {
+	Gtk::TreeRow row(*dtm->get_iter(path));
+	row[dcs.timeout] = new_text;
+	Glib::ustring device = row[dcs.name];
+	Atomic a;
+
+	for (const Combo<TimeoutType>::Info *i = timeout_info; i->name; i++) {
+		if (Glib::ustring(i->name) == new_text) {
+			std::map<std::string, TimeoutType> &dt = prefs.device_timeout.write_ref(a);
+			dt[device] = i->value;
+			return;
+		}
+	}
+
+	std::map<std::string, TimeoutType> &dt = prefs.device_timeout.write_ref(a);
+	dt.erase(device);
+}
+
 void Prefs::set_button_label() {
 	blabel->set_text(prefs.button.ref().get_button_text());
 }
diff --git a/prefs.h b/prefs.h
index 0991550..c76cc47 100644
--- a/prefs.h
+++ b/prefs.h
@@ -36,6 +36,7 @@ private:
 	void on_select_button();
 	void on_button_editing_started(Gtk::CellEditable* editable, const Glib::ustring& path);
 	void on_device_toggled(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter);
+	void on_device_timeout_changed(const Glib::ustring& path, const Glib::ustring& new_text);
 	bool select_row(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter, std::string name);
 
 	class ExceptionColumns : public Gtk::TreeModel::ColumnRecord {
@@ -48,11 +49,19 @@ private:
 	Glib::RefPtr<Gtk::ListStore> tm;
 	Gtk::TreeView* tv;
 
+	class Single : public Gtk::TreeModel::ColumnRecord {
+	public:
+		Single() { add(name); }
+		Gtk::TreeModelColumn<Glib::ustring> name;
+	};
+	Single timeout_columns;
+
 	class DeviceColumns : public Gtk::TreeModel::ColumnRecord {
 	public:
-		DeviceColumns() { add(enabled); add(name); }
+		DeviceColumns() { add(enabled); add(name); add(timeout); }
 		Gtk::TreeModelColumn<bool> enabled;
 		Gtk::TreeModelColumn<Glib::ustring> name;
+		Gtk::TreeModelColumn<Glib::ustring> timeout;
 	};
 	DeviceColumns dcs;
 	Gtk::TreeView* dtv;