From a36625a482585e86d465df1eaa3669c1c4390a20 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Wed, 15 Aug 2018 16:47:02 +1000
Subject: [PATCH 1/3] Implement mousedown operation

This allows you to move the cursor off the surface while dragging its
scrollbar.
---
 include/sway/input/seat.h |  4 ++++
 sway/input/cursor.c       | 23 +++++++++++++++++++++++
 sway/input/seat.c         | 24 +++++++++++++++++++++++-
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 9dfb0714..fb03b609 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -56,6 +56,7 @@ struct sway_seat {
 	// Operations (drag and resize)
 	enum {
 		OP_NONE,
+		OP_MOUSEDOWN,
 		OP_MOVE,
 		OP_RESIZE_FLOATING,
 		OP_RESIZE_TILING,
@@ -157,6 +158,9 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface);
 
 void drag_icon_update_position(struct sway_drag_icon *icon);
 
+void seat_begin_mousedown(struct sway_seat *seat, struct sway_container *con,
+		uint32_t button, double sx, double sy);
+
 void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
 		uint32_t button);
 
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 3b70b471..bd0030f0 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -215,6 +215,18 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont,
 	return edge;
 }
 
+static void handle_mousedown_motion(struct sway_seat *seat,
+		struct sway_cursor *cursor, uint32_t time_msec) {
+	struct sway_container *con = seat->op_container;
+	if (seat_is_input_allowed(seat, con->sway_view->surface)) {
+		double moved_x = cursor->cursor->x - seat->op_ref_lx;
+		double moved_y = cursor->cursor->y - seat->op_ref_ly;
+		double sx = seat->op_ref_con_lx + moved_x;
+		double sy = seat->op_ref_con_ly + moved_y;
+		wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy);
+	}
+}
+
 static void handle_move_motion(struct sway_seat *seat,
 		struct sway_cursor *cursor) {
 	struct sway_container *con = seat->op_container;
@@ -397,6 +409,9 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 
 	if (seat->operation != OP_NONE) {
 		switch (seat->operation) {
+		case OP_MOUSEDOWN:
+			handle_mousedown_motion(seat, cursor, time_msec);
+			break;
 		case OP_MOVE:
 			handle_move_motion(seat, cursor);
 			break;
@@ -743,6 +758,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
 		}
 	}
 
+	// Handle mousedown on a container surface
+	if (surface && cont && state == WLR_BUTTON_PRESSED) {
+		seat_set_focus(seat, cont);
+		seat_pointer_notify_button(seat, time_msec, button, state);
+		seat_begin_mousedown(seat, cont, button, sx, sy);
+		return;
+	}
+
 	// Handle clicking a container surface
 	if (cont) {
 		seat_set_focus(seat, cont);
diff --git a/sway/input/seat.c b/sway/input/seat.c
index fa41904a..045bf91a 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -954,6 +954,17 @@ struct seat_config *seat_get_config(struct sway_seat *seat) {
 	return NULL;
 }
 
+void seat_begin_mousedown(struct sway_seat *seat, struct sway_container *con,
+		uint32_t button, double sx, double sy) {
+	seat->operation = OP_MOUSEDOWN;
+	seat->op_container = con;
+	seat->op_button = button;
+	seat->op_ref_lx = seat->cursor->cursor->x;
+	seat->op_ref_ly = seat->cursor->cursor->y;
+	seat->op_ref_con_lx = sx;
+	seat->op_ref_con_ly = sy;
+}
+
 void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
 		uint32_t button) {
 	if (!seat->cursor) {
@@ -1007,6 +1018,7 @@ void seat_begin_resize_tiling(struct sway_seat *seat,
 }
 
 void seat_end_mouse_operation(struct sway_seat *seat) {
+	int operation = seat->operation;
 	if (seat->operation == OP_MOVE) {
 		// We "move" the container to its own location so it discovers its
 		// output again.
@@ -1015,7 +1027,17 @@ void seat_end_mouse_operation(struct sway_seat *seat) {
 	}
 	seat->operation = OP_NONE;
 	seat->op_container = NULL;
-	cursor_set_image(seat->cursor, "left_ptr", NULL);
+	if (operation == OP_MOUSEDOWN) {
+		// Set the cursor's previous coords to the x/y at the start of the
+		// operation, so the container change will be detected if using
+		// focus_follows_mouse and the cursor moved off the original container
+		// during the operation.
+		seat->cursor->previous.x = seat->op_ref_lx;
+		seat->cursor->previous.y = seat->op_ref_ly;
+		cursor_send_pointer_motion(seat->cursor, 0, true);
+	} else {
+		cursor_set_image(seat->cursor, "left_ptr", NULL);
+	}
 }
 
 void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,

From b637b61a7a25219991280717d9bf8a463ed4d8a8 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Thu, 16 Aug 2018 09:12:48 +1000
Subject: [PATCH 2/3] Rename mousedown to down and make seat operation a named
 enum

---
 include/sway/input/seat.h | 19 ++++++++++---------
 sway/input/cursor.c       |  8 ++++----
 sway/input/seat.c         |  8 ++++----
 3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index fb03b609..c07db61c 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -35,6 +35,14 @@ struct sway_drag_icon {
 	struct wl_listener destroy;
 };
 
+enum sway_seat_operation {
+	OP_NONE,
+	OP_DOWN,
+	OP_MOVE,
+	OP_RESIZE_FLOATING,
+	OP_RESIZE_TILING,
+};
+
 struct sway_seat {
 	struct wlr_seat *wlr_seat;
 	struct sway_cursor *cursor;
@@ -54,14 +62,7 @@ struct sway_seat {
 	double touch_x, touch_y;
 
 	// Operations (drag and resize)
-	enum {
-		OP_NONE,
-		OP_MOUSEDOWN,
-		OP_MOVE,
-		OP_RESIZE_FLOATING,
-		OP_RESIZE_TILING,
-	} operation;
-
+	enum sway_seat_operation operation;
 	struct sway_container *op_container;
 	enum wlr_edges op_resize_edge;
 	uint32_t op_button;
@@ -158,7 +159,7 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface);
 
 void drag_icon_update_position(struct sway_drag_icon *icon);
 
-void seat_begin_mousedown(struct sway_seat *seat, struct sway_container *con,
+void seat_begin_down(struct sway_seat *seat, struct sway_container *con,
 		uint32_t button, double sx, double sy);
 
 void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index bd0030f0..5a2743e3 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -215,7 +215,7 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont,
 	return edge;
 }
 
-static void handle_mousedown_motion(struct sway_seat *seat,
+static void handle_down_motion(struct sway_seat *seat,
 		struct sway_cursor *cursor, uint32_t time_msec) {
 	struct sway_container *con = seat->op_container;
 	if (seat_is_input_allowed(seat, con->sway_view->surface)) {
@@ -409,8 +409,8 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 
 	if (seat->operation != OP_NONE) {
 		switch (seat->operation) {
-		case OP_MOUSEDOWN:
-			handle_mousedown_motion(seat, cursor, time_msec);
+		case OP_DOWN:
+			handle_down_motion(seat, cursor, time_msec);
 			break;
 		case OP_MOVE:
 			handle_move_motion(seat, cursor);
@@ -762,7 +762,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
 	if (surface && cont && state == WLR_BUTTON_PRESSED) {
 		seat_set_focus(seat, cont);
 		seat_pointer_notify_button(seat, time_msec, button, state);
-		seat_begin_mousedown(seat, cont, button, sx, sy);
+		seat_begin_down(seat, cont, button, sx, sy);
 		return;
 	}
 
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 045bf91a..cc7c28d8 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -954,9 +954,9 @@ struct seat_config *seat_get_config(struct sway_seat *seat) {
 	return NULL;
 }
 
-void seat_begin_mousedown(struct sway_seat *seat, struct sway_container *con,
+void seat_begin_down(struct sway_seat *seat, struct sway_container *con,
 		uint32_t button, double sx, double sy) {
-	seat->operation = OP_MOUSEDOWN;
+	seat->operation = OP_DOWN;
 	seat->op_container = con;
 	seat->op_button = button;
 	seat->op_ref_lx = seat->cursor->cursor->x;
@@ -1018,7 +1018,7 @@ void seat_begin_resize_tiling(struct sway_seat *seat,
 }
 
 void seat_end_mouse_operation(struct sway_seat *seat) {
-	int operation = seat->operation;
+	enum sway_seat_operation operation = seat->operation;
 	if (seat->operation == OP_MOVE) {
 		// We "move" the container to its own location so it discovers its
 		// output again.
@@ -1027,7 +1027,7 @@ void seat_end_mouse_operation(struct sway_seat *seat) {
 	}
 	seat->operation = OP_NONE;
 	seat->op_container = NULL;
-	if (operation == OP_MOUSEDOWN) {
+	if (operation == OP_DOWN) {
 		// Set the cursor's previous coords to the x/y at the start of the
 		// operation, so the container change will be detected if using
 		// focus_follows_mouse and the cursor moved off the original container

From 07a897b3b797b99022a9dfffffc0af2ff50aea85 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Sat, 18 Aug 2018 09:29:18 +1000
Subject: [PATCH 3/3] Don't send motion if the cursor hasn't moved

Prevents GTK+ comboboxes from immediately closing.
---
 include/sway/input/seat.h | 1 +
 sway/input/cursor.c       | 1 +
 sway/input/seat.c         | 5 ++++-
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index c07db61c..5c404ecd 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -70,6 +70,7 @@ struct sway_seat {
 	double op_ref_lx, op_ref_ly;         // cursor's x/y at start of op
 	double op_ref_width, op_ref_height;  // container's size at start of op
 	double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op
+	bool op_moved;                       // if the mouse moved during a down op
 
 	uint32_t last_button;
 	uint32_t last_button_serial;
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 5a2743e3..37fb203d 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -225,6 +225,7 @@ static void handle_down_motion(struct sway_seat *seat,
 		double sy = seat->op_ref_con_ly + moved_y;
 		wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy);
 	}
+	seat->op_moved = true;
 }
 
 static void handle_move_motion(struct sway_seat *seat,
diff --git a/sway/input/seat.c b/sway/input/seat.c
index cc7c28d8..9d46e760 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -963,6 +963,7 @@ void seat_begin_down(struct sway_seat *seat, struct sway_container *con,
 	seat->op_ref_ly = seat->cursor->cursor->y;
 	seat->op_ref_con_lx = sx;
 	seat->op_ref_con_ly = sy;
+	seat->op_moved = false;
 }
 
 void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
@@ -1034,7 +1035,9 @@ void seat_end_mouse_operation(struct sway_seat *seat) {
 		// during the operation.
 		seat->cursor->previous.x = seat->op_ref_lx;
 		seat->cursor->previous.y = seat->op_ref_ly;
-		cursor_send_pointer_motion(seat->cursor, 0, true);
+		if (seat->op_moved) {
+			cursor_send_pointer_motion(seat->cursor, 0, true);
+		}
 	} else {
 		cursor_set_image(seat->cursor, "left_ptr", NULL);
 	}