← easystroke

Allow gestures to be distinguished by modifiers

4fab28cee262e2398283abe593002f8aa10eded6 · Thomas Jaeger · Sep 23, 2012 00:36

+43 −13 · 6 files changed

  • gesture.cc +4 −2
  • gesture.h +11 −6
  • grabber.cc +7 −0
  • grabber.h +1 −0
  • main.cc +12 −4
  • win.cc +8 −1
diff --git a/gesture.cc b/gesture.cc
index 8d2a697..d13e100 100644
--- a/gesture.cc
+++ b/gesture.cc
@@ -28,7 +28,7 @@ RTriple create_triple(float x, float y, Time t) {
 	return e;
 }
 
-Stroke::Stroke(PreStroke &ps, int trigger_, int button_, bool timeout_) : button(button_), timeout(timeout_) {
+Stroke::Stroke(PreStroke &ps, int trigger_, int button_, unsigned int modifiers_, bool timeout_) : button(button_), modifiers(modifiers_), timeout(timeout_) {
 	trigger = (trigger_ == get_default_button()) ? 0 : trigger_;
 
 	if (ps.valid()) {
@@ -54,6 +54,8 @@ int Stroke::compare(RStroke a, RStroke b, double &score) {
 		if (a->trigger + b->trigger != get_default_button())
 			return -1;
 	}
+	if (a->modifiers != b->modifiers)
+		return -1;
 	if (!a->stroke || !b->stroke) {
 		if (!a->stroke && !b->stroke) {
 			score = 1.0;
@@ -102,5 +104,5 @@ RStroke Stroke::trefoil() {
 		double r = exp(1.0 + sin(6.0*M_PI*i/n)) + 2.0;
 		s.add(create_triple(r*cos(phi), r*sin(phi), i));
 	}
-	return Stroke::create(s, 0, 0, false);
+	return Stroke::create(s, 0, 0, AnyModifier, false);
 }
diff --git a/gesture.h b/gesture.h
index ee98077..6edfcd4 100644
--- a/gesture.h
+++ b/gesture.h
@@ -24,7 +24,7 @@
 #include <boost/serialization/version.hpp>
 #include <boost/serialization/split_member.hpp>
 
-#include <X11/X.h> // Time
+#include <X11/X.h>
 
 #define STROKE_SIZE 64
 
@@ -76,7 +76,7 @@ public:
 	};
 
 private:
-	Stroke(PreStroke &s, int trigger_, int button_, bool timeout_);
+	Stroke(PreStroke &s, int trigger_, int button_, unsigned int modifiers_, bool timeout_);
 
 	Glib::RefPtr<Gdk::Pixbuf> draw_(int size, double width = 2.0, bool inv = false) const;
 	mutable Glib::RefPtr<Gdk::Pixbuf> pb[2];
@@ -93,6 +93,7 @@ private:
 		ar & button;
 		ar & trigger;
 		ar & timeout;
+		ar & modifiers;
 	}
 	template<class Archive> void load(Archive & ar, const unsigned int version) {
 		std::vector<Point> ps;
@@ -113,17 +114,21 @@ private:
 		if (version < 3)
 			return;
 		ar & timeout;
+		if (version < 5)
+			return;
+		ar & modifiers;
 	}
 
 public:
 	int trigger;
 	int button;
+	unsigned int modifiers;
 	bool timeout;
 	boost::shared_ptr<stroke_t> stroke;
 
-	Stroke() : trigger(0), button(0), timeout(false) {}
-	static RStroke create(PreStroke &s, int trigger_, int button_, bool timeout_) {
-		return RStroke(new Stroke(s, trigger_, button_, timeout_));
+	Stroke() : trigger(0), button(0), modifiers(AnyModifier), timeout(false) {}
+	static RStroke create(PreStroke &s, int trigger_, int button_, unsigned int modifiers_, bool timeout_) {
+		return RStroke(new Stroke(s, trigger_, button_, modifiers_, timeout_));
 	}
         Glib::RefPtr<Gdk::Pixbuf> draw(int size, double width = 2.0, bool inv = false) const;
 	void draw(Cairo::RefPtr<Cairo::Surface> surface, int x, int y, int w, int h, double width = 2.0, bool inv = false) const;
@@ -141,7 +146,7 @@ public:
 	double time(int n) const { return stroke_get_time(stroke.get(), n); }
 	bool is_timeout() const { return timeout; }
 };
-BOOST_CLASS_VERSION(Stroke, 4)
+BOOST_CLASS_VERSION(Stroke, 5)
 BOOST_CLASS_VERSION(Stroke::Point, 1)
 
 class PreStroke : public std::vector<RTriple> {
diff --git a/grabber.cc b/grabber.cc
index 726d060..3c2e2e5 100644
--- a/grabber.cc
+++ b/grabber.cc
@@ -503,6 +503,13 @@ bool Grabber::is_click_hold(guint b) {
 	return false;
 }
 
+guint Grabber::get_default_mods(guint button) {
+	for (std::vector<ButtonInfo>::const_iterator i = buttons.begin(); i != buttons.end(); ++i)
+		if (i->button == button)
+			return i->state;
+	return AnyModifier;
+}
+
 int get_default_button() {
 	if (grabber)
 		return grabber->get_default_button();
diff --git a/grabber.h b/grabber.h
index c737297..6b33f70 100644
--- a/grabber.h
+++ b/grabber.h
@@ -120,6 +120,7 @@ public:
 	void hierarchy_changed(XIHierarchyEvent *);
 
 	int get_default_button() { return grabbed_button.button; }
+	guint get_default_mods(guint button);
 
 	void unminimize();
 };
diff --git a/main.cc b/main.cc
index 8b935f1..75bf8f3 100644
--- a/main.cc
+++ b/main.cc
@@ -47,7 +47,7 @@ extern Source<bool> disabled;
 bool experimental = false;
 int verbosity = 0;
 const char *prefs_versions[] = { "-0.5.5", "-0.4.1", "-0.4.0", "", NULL };
-const char *actions_versions[] = { "-0.4.1", "-0.4.0", "", NULL };
+const char *actions_versions[] = { "-0.5.6", "-0.4.1", "-0.4.0", "", NULL };
 Source<Window> current_app_window(None);
 std::string config_dir;
 Win *win = NULL;
@@ -57,6 +57,7 @@ bool in_proximity = false;
 boost::shared_ptr<sigc::slot<void, RStroke> > stroke_action;
 Grabber::XiDevice *current_dev = 0;
 std::set<guint> xinput_pressed; // TODO get rid of
+guint modifiers;
 
 static bool show_gui = false;
 static bool no_dbus = false;
@@ -844,7 +845,7 @@ class StrokeHandler : public Handler, public sigc::trackable {
 			c.reset(new PreStroke);
 		if (b && prefs.advanced_ignore.get())
 			c.reset(new PreStroke);
-		return Stroke::create(*c, button, b, false);
+		return Stroke::create(*c, button, b, modifiers, false);
 	}
 
 	bool timeout() {
@@ -856,7 +857,7 @@ class StrokeHandler : public Handler, public sigc::trackable {
 			c.reset(new PreStroke);
 		RStroke s;
 		if (prefs.timeout_gestures.get() || grabber->is_click_hold(button))
-			s = Stroke::create(*c, button, 0, true);
+			s = Stroke::create(*c, button, 0, modifiers, true);
 		parent->replace_child(AdvancedHandler::create(s, last, button, 0, cur));
 		XFlush(dpy);
 		return false;
@@ -864,7 +865,7 @@ class StrokeHandler : public Handler, public sigc::trackable {
 
 	void do_instant() {
 		PreStroke ps;
-		RStroke s = Stroke::create(ps, button, button, false);
+		RStroke s = Stroke::create(ps, button, button, modifiers, false);
 		parent->replace_child(AdvancedHandler::create(s, orig, button, button, cur));
 	}
 
@@ -1466,6 +1467,13 @@ void Main::handle_xi2_event(XIDeviceEvent *event) {
 			}
 			if (current_dev->master)
 				XISetClientPointer(dpy, None, current_dev->master);
+			if (!xinput_pressed.size()) {
+				guint default_mods = grabber->get_default_mods(event->detail);
+				if (default_mods == AnyModifier || default_mods == (guint)event->mods.base)
+					modifiers = AnyModifier;
+				else
+					modifiers = event->mods.base;
+			}
 			xinput_pressed.insert(event->detail);
 			H->press(event->detail, create_triple(event->root_x, event->root_y, event->time));
 			break;
diff --git a/win.cc b/win.cc
index 7eaba8c..d9ffd36 100644
--- a/win.cc
+++ b/win.cc
@@ -69,8 +69,15 @@ void Stroke::draw(Cairo::RefPtr<Cairo::Surface> surface, int x, int y, int w, in
 	}
 	ctx->restore();
 	Glib::ustring str;
+	if (modifiers != AnyModifier) {
+		str = Gtk::AccelGroup::get_label(0, (Gdk::ModifierType)modifiers);
+		if (str == "")
+			str = "<>";
+		else
+			str = "<" + str.substr(0, str.size()-1) + ">";
+	}
 	if (trigger)
-		str = Glib::ustring::compose("%1\xE2\x86\x92", trigger);
+		str += Glib::ustring::compose("%1\xE2\x86\x92", trigger);
 	if (timeout)
 		str += "x";
 	if (button)