From 499150a91b706b9829ca763ede9b97c573b51cb7 Mon Sep 17 00:00:00 2001
From: Ian Fan <ianfan0@gmail.com>
Date: Wed, 17 Oct 2018 20:21:27 +0100
Subject: [PATCH] swaybar: separate input code to new file

---
 include/swaybar/bar.h   |  38 +-----
 include/swaybar/i3bar.h |   4 +-
 include/swaybar/input.h |  49 +++++++
 swaybar/bar.c           | 248 +---------------------------------
 swaybar/i3bar.c         |  30 +----
 swaybar/input.c         | 286 ++++++++++++++++++++++++++++++++++++++++
 swaybar/meson.build     |   1 +
 7 files changed, 340 insertions(+), 316 deletions(-)
 create mode 100644 include/swaybar/input.h
 create mode 100644 swaybar/input.c

diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h
index 58e2dee62..95b20510e 100644
--- a/include/swaybar/bar.h
+++ b/include/swaybar/bar.h
@@ -1,6 +1,7 @@
 #ifndef _SWAYBAR_BAR_H
 #define _SWAYBAR_BAR_H
 #include <wayland-client.h>
+#include "input.h"
 #include "pool-buffer.h"
 #include "wlr-layer-shell-unstable-v1-client-protocol.h"
 #include "xdg-output-unstable-v1-client-protocol.h"
@@ -10,42 +11,6 @@ struct swaybar_output;
 struct swaybar_workspace;
 struct loop;
 
-struct swaybar_pointer {
-	struct wl_pointer *pointer;
-	struct wl_cursor_theme *cursor_theme;
-	struct wl_cursor_image *cursor_image;
-	struct wl_surface *cursor_surface;
-	struct swaybar_output *current;
-	int x, y;
-};
-
-enum x11_button {
-	NONE,
-	LEFT,
-	MIDDLE,
-	RIGHT,
-	SCROLL_UP,
-	SCROLL_DOWN,
-	SCROLL_LEFT,
-	SCROLL_RIGHT,
-	BACK,
-	FORWARD,
-};
-
-enum hotspot_event_handling {
-	HOTSPOT_IGNORE,
-	HOTSPOT_PROCESS,
-};
-
-struct swaybar_hotspot {
-	struct wl_list link; // swaybar_output::hotspots
-	int x, y, width, height;
-	enum hotspot_event_handling (*callback)(struct swaybar_output *output,
-			int x, int y, enum x11_button button, void *data);
-	void (*destroy)(void *data);
-	void *data;
-};
-
 struct swaybar {
 	char *id;
 	char *mode;
@@ -125,7 +90,6 @@ void bar_teardown(struct swaybar *bar);
  * Returns true if the bar is now visible, otherwise false.
  */
 bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
-void free_hotspots(struct wl_list *list);
 void free_workspaces(struct wl_list *list);
 
 #endif
diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h
index d4a48e073..3f1ecc259 100644
--- a/include/swaybar/i3bar.h
+++ b/include/swaybar/i3bar.h
@@ -1,7 +1,7 @@
 #ifndef _SWAYBAR_I3BAR_H
 #define _SWAYBAR_I3BAR_H
 
-#include "bar.h"
+#include "input.h"
 #include "status_line.h"
 
 struct i3bar_block {
@@ -28,7 +28,5 @@ void i3bar_block_unref(struct i3bar_block *block);
 bool i3bar_handle_readable(struct status_line *status);
 enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
 		struct i3bar_block *block, int x, int y, enum x11_button button);
-enum x11_button wl_button_to_x11_button(uint32_t button);
-enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value);
 
 #endif
diff --git a/include/swaybar/input.h b/include/swaybar/input.h
new file mode 100644
index 000000000..a552e7aca
--- /dev/null
+++ b/include/swaybar/input.h
@@ -0,0 +1,49 @@
+#ifndef _SWAYBAR_INPUT_H
+#define _SWAYBAR_INPUT_H
+
+#include <wayland-client.h>
+#include "list.h"
+
+struct swaybar_output;
+
+struct swaybar_pointer {
+	struct wl_pointer *pointer;
+	struct wl_cursor_theme *cursor_theme;
+	struct wl_cursor_image *cursor_image;
+	struct wl_surface *cursor_surface;
+	struct swaybar_output *current;
+	int x, y;
+};
+
+enum x11_button {
+	NONE,
+	LEFT,
+	MIDDLE,
+	RIGHT,
+	SCROLL_UP,
+	SCROLL_DOWN,
+	SCROLL_LEFT,
+	SCROLL_RIGHT,
+	BACK,
+	FORWARD,
+};
+
+enum hotspot_event_handling {
+	HOTSPOT_IGNORE,
+	HOTSPOT_PROCESS,
+};
+
+struct swaybar_hotspot {
+	struct wl_list link; // swaybar_output::hotspots
+	int x, y, width, height;
+	enum hotspot_event_handling (*callback)(struct swaybar_output *output,
+			int x, int y, enum x11_button button, void *data);
+	void (*destroy)(void *data);
+	void *data;
+};
+
+extern const struct wl_seat_listener seat_listener;
+
+void free_hotspots(struct wl_list *list);
+
+#endif
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 0deba72df..5e9767b27 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -11,14 +11,10 @@
 #include <wayland-client.h>
 #include <wayland-cursor.h>
 #include <wlr/util/log.h>
-#ifdef __FreeBSD__
-#include <dev/evdev/input-event-codes.h>
-#else
-#include <linux/input-event-codes.h>
-#endif
 #include "swaybar/bar.h"
 #include "swaybar/config.h"
 #include "swaybar/i3bar.h"
+#include "swaybar/input.h"
 #include "swaybar/ipc.h"
 #include "swaybar/status_line.h"
 #include "swaybar/render.h"
@@ -36,17 +32,6 @@ static void bar_init(struct swaybar *bar) {
 	wl_list_init(&bar->outputs);
 }
 
-void free_hotspots(struct wl_list *list) {
-	struct swaybar_hotspot *hotspot, *tmp;
-	wl_list_for_each_safe(hotspot, tmp, list, link) {
-		wl_list_remove(&hotspot->link);
-		if (hotspot->destroy) {
-			hotspot->destroy(hotspot->data);
-		}
-		free(hotspot);
-	}
-}
-
 void free_workspaces(struct wl_list *list) {
 	struct swaybar_workspace *ws, *tmp;
 	wl_list_for_each_safe(ws, tmp, list, link) {
@@ -107,237 +92,6 @@ struct zwlr_layer_surface_v1_listener layer_surface_listener = {
 	.closed = layer_surface_closed,
 };
 
-static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
-		uint32_t serial, struct wl_surface *surface,
-		wl_fixed_t surface_x, wl_fixed_t surface_y) {
-	struct swaybar *bar = data;
-	struct swaybar_pointer *pointer = &bar->pointer;
-	struct swaybar_output *output;
-	wl_list_for_each(output, &bar->outputs, link) {
-		if (output->surface == surface) {
-			pointer->current = output;
-			break;
-		}
-	}
-	int max_scale = 1;
-	struct swaybar_output *_output;
-	wl_list_for_each(_output, &bar->outputs, link) {
-		if (_output->scale > max_scale) {
-			max_scale = _output->scale;
-		}
-	}
-	wl_surface_set_buffer_scale(pointer->cursor_surface, max_scale);
-	wl_surface_attach(pointer->cursor_surface,
-			wl_cursor_image_get_buffer(pointer->cursor_image), 0, 0);
-	wl_pointer_set_cursor(wl_pointer, serial, pointer->cursor_surface,
-			pointer->cursor_image->hotspot_x / max_scale,
-			pointer->cursor_image->hotspot_y / max_scale);
-	wl_surface_commit(pointer->cursor_surface);
-}
-
-static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
-		uint32_t serial, struct wl_surface *surface) {
-	struct swaybar *bar = data;
-	bar->pointer.current = NULL;
-}
-
-static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
-		uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
-	struct swaybar *bar = data;
-	bar->pointer.x = wl_fixed_to_int(surface_x);
-	bar->pointer.y = wl_fixed_to_int(surface_y);
-}
-
-static bool check_bindings(struct swaybar *bar, uint32_t x11_button,
-		uint32_t state) {
-	bool released = state == WL_POINTER_BUTTON_STATE_RELEASED;
-	for (int i = 0; i < bar->config->bindings->length; i++) {
-		struct swaybar_binding *binding = bar->config->bindings->items[i];
-		if (binding->button == x11_button && binding->release == released) {
-			ipc_execute_binding(bar, binding);
-			return true;
-		}
-	}
-	return false;
-}
-
-static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
-		uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
-	struct swaybar *bar = data;
-	struct swaybar_pointer *pointer = &bar->pointer;
-	struct swaybar_output *output = pointer->current;
-	if (!sway_assert(output, "button with no active output")) {
-		return;
-	}
-
-	if (check_bindings(bar, wl_button_to_x11_button(button), state)) {
-		return;
-	}
-
-	if (state != WL_POINTER_BUTTON_STATE_PRESSED) {
-		return;
-	}
-	struct swaybar_hotspot *hotspot;
-	wl_list_for_each(hotspot, &output->hotspots, link) {
-		double x = pointer->x * output->scale;
-		double y = pointer->y * output->scale;
-		if (x >= hotspot->x
-				&& y >= hotspot->y
-				&& x < hotspot->x + hotspot->width
-				&& y < hotspot->y + hotspot->height) {
-			if (HOTSPOT_IGNORE == hotspot->callback(output, pointer->x, pointer->y,
-					wl_button_to_x11_button(button), hotspot->data)) {
-				return;
-			}
-		}
-	}
-}
-
-static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
-		uint32_t time, uint32_t axis, wl_fixed_t value) {
-	struct swaybar *bar = data;
-	struct swaybar_pointer *pointer = &bar->pointer;
-	struct swaybar_output *output = bar->pointer.current;
-	if (!sway_assert(output, "axis with no active output")) {
-		return;
-	}
-
-	// If there is a button press binding, execute it, skip default behavior,
-	// and check button release bindings
-	if (check_bindings(bar, wl_axis_to_x11_button(axis, value),
-			WL_POINTER_BUTTON_STATE_PRESSED)) {
-		check_bindings(bar, wl_axis_to_x11_button(axis, value),
-				WL_POINTER_BUTTON_STATE_RELEASED);
-		return;
-	}
-
-	struct swaybar_hotspot *hotspot;
-	wl_list_for_each(hotspot, &output->hotspots, link) {
-		double x = pointer->x * output->scale;
-		double y = pointer->y * output->scale;
-		if (x >= hotspot->x
-				&& y >= hotspot->y
-				&& x < hotspot->x + hotspot->width
-				&& y < hotspot->y + hotspot->height) {
-			if (HOTSPOT_IGNORE == hotspot->callback(
-					output, pointer->x, pointer->y,
-					wl_axis_to_x11_button(axis, value), hotspot->data)) {
-				return;
-			}
-		}
-	}
-
-	double amt = wl_fixed_to_double(value);
-	if (amt == 0.0) {
-		return;
-	}
-
-	// last doesn't actually need initialization,
-	// but gcc (7.3.1) is too dumb to figure it out
-	struct swaybar_workspace *first = NULL;
-	struct swaybar_workspace *active = NULL;
-	struct swaybar_workspace *last = NULL;
-
-	struct swaybar_workspace *iter;
-	wl_list_for_each(iter, &output->workspaces, link) {
-		if (!first) {
-			first = iter;
-		}
-
-		if (iter->visible) {
-			active = iter;
-		}
-
-		last = iter;
-	}
-
-	if (!sway_assert(active, "axis with null workspace")) {
-		return;
-	}
-
-	struct swaybar_workspace *new;
-
-	if (amt > 0.0) {
-		if (active == first) {
-			if (!bar->config->wrap_scroll) {
-				return;
-			}
-			new = last;
-		}
-
-		new = wl_container_of(active->link.prev, new, link);
-	} else {
-		if (active == last) {
-			if (!bar->config->wrap_scroll) {
-				return;
-			}
-			new = first;
-		}
-
-		new = wl_container_of(active->link.next, new, link);
-	}
-
-	ipc_send_workspace_command(bar, new->name);
-
-	// Check button release bindings
-	check_bindings(bar, wl_axis_to_x11_button(axis, value),
-			WL_POINTER_BUTTON_STATE_RELEASED);
-}
-
-static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) {
-	// Who cares
-}
-
-static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
-		uint32_t axis_source) {
-	// Who cares
-}
-
-static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
-		uint32_t time, uint32_t axis) {
-	// Who cares
-}
-
-static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
-		uint32_t axis, int32_t discrete) {
-	// Who cares
-}
-
-struct wl_pointer_listener pointer_listener = {
-	.enter = wl_pointer_enter,
-	.leave = wl_pointer_leave,
-	.motion = wl_pointer_motion,
-	.button = wl_pointer_button,
-	.axis = wl_pointer_axis,
-	.frame = wl_pointer_frame,
-	.axis_source = wl_pointer_axis_source,
-	.axis_stop = wl_pointer_axis_stop,
-	.axis_discrete = wl_pointer_axis_discrete,
-};
-
-static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
-		enum wl_seat_capability caps) {
-	struct swaybar *bar = data;
-	if (bar->pointer.pointer != NULL) {
-		wl_pointer_release(bar->pointer.pointer);
-		bar->pointer.pointer = NULL;
-	}
-	if ((caps & WL_SEAT_CAPABILITY_POINTER)) {
-		bar->pointer.pointer = wl_seat_get_pointer(wl_seat);
-		wl_pointer_add_listener(bar->pointer.pointer, &pointer_listener, bar);
-	}
-}
-
-static void seat_handle_name(void *data, struct wl_seat *wl_seat,
-		const char *name) {
-	// Who cares
-}
-
-const struct wl_seat_listener seat_listener = {
-	.capabilities = seat_handle_capabilities,
-	.name = seat_handle_name,
-};
-
 static void add_layer_surface(struct swaybar_output *output) {
 	if (output->layer_surface) {
 		return;
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c
index 1d754808d..3ea74e131 100644
--- a/swaybar/i3bar.c
+++ b/swaybar/i3bar.c
@@ -9,6 +9,7 @@
 #include "swaybar/bar.h"
 #include "swaybar/config.h"
 #include "swaybar/i3bar.h"
+#include "swaybar/input.h"
 #include "swaybar/status_line.h"
 
 void i3bar_block_unref(struct i3bar_block *block) {
@@ -284,32 +285,3 @@ enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
 	json_object_put(event_json);
 	return HOTSPOT_IGNORE;
 }
-
-enum x11_button wl_button_to_x11_button(uint32_t button) {
-	switch (button) {
-	case BTN_LEFT:
-		return LEFT;
-	case BTN_MIDDLE:
-		return MIDDLE;
-	case BTN_RIGHT:
-		return RIGHT;
-	case BTN_SIDE:
-		return BACK;
-	case BTN_EXTRA:
-		return FORWARD;
-	default:
-		return NONE;
-	}
-}
-
-enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value) {
-	switch (axis) {
-	case WL_POINTER_AXIS_VERTICAL_SCROLL:
-		return wl_fixed_to_double(value) < 0 ? SCROLL_UP : SCROLL_DOWN;
-	case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
-		return wl_fixed_to_double(value) < 0 ? SCROLL_LEFT : SCROLL_RIGHT;
-	default:
-		wlr_log(WLR_DEBUG, "Unexpected axis value on mouse scroll");
-		return NONE;
-	}
-}
diff --git a/swaybar/input.c b/swaybar/input.c
new file mode 100644
index 000000000..31137f448
--- /dev/null
+++ b/swaybar/input.c
@@ -0,0 +1,286 @@
+#include <assert.h>
+#ifdef __FreeBSD__
+#include <dev/evdev/input-event-codes.h>
+#else
+#include <linux/input-event-codes.h>
+#endif
+#include <wayland-client.h>
+#include <wayland-cursor.h>
+#include <wlr/util/log.h>
+#include "list.h"
+#include "log.h"
+#include "swaybar/bar.h"
+#include "swaybar/config.h"
+#include "swaybar/input.h"
+#include "swaybar/ipc.h"
+
+void free_hotspots(struct wl_list *list) {
+	struct swaybar_hotspot *hotspot, *tmp;
+	wl_list_for_each_safe(hotspot, tmp, list, link) {
+		wl_list_remove(&hotspot->link);
+		if (hotspot->destroy) {
+			hotspot->destroy(hotspot->data);
+		}
+		free(hotspot);
+	}
+}
+
+static enum x11_button wl_button_to_x11_button(uint32_t button) {
+	switch (button) {
+	case BTN_LEFT:
+		return LEFT;
+	case BTN_MIDDLE:
+		return MIDDLE;
+	case BTN_RIGHT:
+		return RIGHT;
+	case BTN_SIDE:
+		return BACK;
+	case BTN_EXTRA:
+		return FORWARD;
+	default:
+		return NONE;
+	}
+}
+
+static enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value) {
+	switch (axis) {
+	case WL_POINTER_AXIS_VERTICAL_SCROLL:
+		return wl_fixed_to_double(value) < 0 ? SCROLL_UP : SCROLL_DOWN;
+	case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
+		return wl_fixed_to_double(value) < 0 ? SCROLL_LEFT : SCROLL_RIGHT;
+	default:
+		wlr_log(WLR_DEBUG, "Unexpected axis value on mouse scroll");
+		return NONE;
+	}
+}
+
+static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
+		uint32_t serial, struct wl_surface *surface,
+		wl_fixed_t surface_x, wl_fixed_t surface_y) {
+	struct swaybar *bar = data;
+	struct swaybar_pointer *pointer = &bar->pointer;
+	struct swaybar_output *output;
+	wl_list_for_each(output, &bar->outputs, link) {
+		if (output->surface == surface) {
+			pointer->current = output;
+			break;
+		}
+	}
+	int max_scale = 1;
+	struct swaybar_output *_output;
+	wl_list_for_each(_output, &bar->outputs, link) {
+		if (_output->scale > max_scale) {
+			max_scale = _output->scale;
+		}
+	}
+	wl_surface_set_buffer_scale(pointer->cursor_surface, max_scale);
+	wl_surface_attach(pointer->cursor_surface,
+			wl_cursor_image_get_buffer(pointer->cursor_image), 0, 0);
+	wl_pointer_set_cursor(wl_pointer, serial, pointer->cursor_surface,
+			pointer->cursor_image->hotspot_x / max_scale,
+			pointer->cursor_image->hotspot_y / max_scale);
+	wl_surface_commit(pointer->cursor_surface);
+}
+
+static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
+		uint32_t serial, struct wl_surface *surface) {
+	struct swaybar *bar = data;
+	bar->pointer.current = NULL;
+}
+
+static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+		uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
+	struct swaybar *bar = data;
+	bar->pointer.x = wl_fixed_to_int(surface_x);
+	bar->pointer.y = wl_fixed_to_int(surface_y);
+}
+
+static bool check_bindings(struct swaybar *bar, uint32_t x11_button,
+		uint32_t state) {
+	bool released = state == WL_POINTER_BUTTON_STATE_RELEASED;
+	for (int i = 0; i < bar->config->bindings->length; i++) {
+		struct swaybar_binding *binding = bar->config->bindings->items[i];
+		if (binding->button == x11_button && binding->release == released) {
+			ipc_execute_binding(bar, binding);
+			return true;
+		}
+	}
+	return false;
+}
+
+static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
+		uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
+	struct swaybar *bar = data;
+	struct swaybar_pointer *pointer = &bar->pointer;
+	struct swaybar_output *output = pointer->current;
+	if (!sway_assert(output, "button with no active output")) {
+		return;
+	}
+
+	if (check_bindings(bar, wl_button_to_x11_button(button), state)) {
+		return;
+	}
+
+	if (state != WL_POINTER_BUTTON_STATE_PRESSED) {
+		return;
+	}
+	struct swaybar_hotspot *hotspot;
+	wl_list_for_each(hotspot, &output->hotspots, link) {
+		double x = pointer->x * output->scale;
+		double y = pointer->y * output->scale;
+		if (x >= hotspot->x
+				&& y >= hotspot->y
+				&& x < hotspot->x + hotspot->width
+				&& y < hotspot->y + hotspot->height) {
+			if (HOTSPOT_IGNORE == hotspot->callback(output, pointer->x, pointer->y,
+					wl_button_to_x11_button(button), hotspot->data)) {
+				return;
+			}
+		}
+	}
+}
+
+static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
+		uint32_t time, uint32_t axis, wl_fixed_t value) {
+	struct swaybar *bar = data;
+	struct swaybar_pointer *pointer = &bar->pointer;
+	struct swaybar_output *output = pointer->current;
+	if (!sway_assert(output, "axis with no active output")) {
+		return;
+	}
+
+	// If there is a button press binding, execute it, skip default behavior,
+	// and check button release bindings
+	if (check_bindings(bar, wl_axis_to_x11_button(axis, value),
+			WL_POINTER_BUTTON_STATE_PRESSED)) {
+		check_bindings(bar, wl_axis_to_x11_button(axis, value),
+				WL_POINTER_BUTTON_STATE_RELEASED);
+		return;
+	}
+
+	struct swaybar_hotspot *hotspot;
+	wl_list_for_each(hotspot, &output->hotspots, link) {
+		double x = pointer->x * output->scale;
+		double y = pointer->y * output->scale;
+		if (x >= hotspot->x
+				&& y >= hotspot->y
+				&& x < hotspot->x + hotspot->width
+				&& y < hotspot->y + hotspot->height) {
+			if (HOTSPOT_IGNORE == hotspot->callback(
+					output, pointer->x, pointer->y,
+					wl_axis_to_x11_button(axis, value), hotspot->data)) {
+				return;
+			}
+		}
+	}
+
+	double amt = wl_fixed_to_double(value);
+	if (amt == 0.0) {
+		return;
+	}
+
+	// last doesn't actually need initialization,
+	// but gcc (7.3.1) is too dumb to figure it out
+	struct swaybar_workspace *first = NULL;
+	struct swaybar_workspace *active = NULL;
+	struct swaybar_workspace *last = NULL;
+
+	struct swaybar_workspace *iter;
+	wl_list_for_each(iter, &output->workspaces, link) {
+		if (!first) {
+			first = iter;
+		}
+
+		if (iter->visible) {
+			active = iter;
+		}
+
+		last = iter;
+	}
+
+	if (!sway_assert(active, "axis with null workspace")) {
+		return;
+	}
+
+	struct swaybar_workspace *new;
+
+	if (amt > 0.0) {
+		if (active == first) {
+			if (!bar->config->wrap_scroll) {
+				return;
+			}
+			new = last;
+		}
+
+		new = wl_container_of(active->link.prev, new, link);
+	} else {
+		if (active == last) {
+			if (!bar->config->wrap_scroll) {
+				return;
+			}
+			new = first;
+		}
+
+		new = wl_container_of(active->link.next, new, link);
+	}
+
+	ipc_send_workspace_command(bar, new->name);
+
+	// Check button release bindings
+	check_bindings(bar, wl_axis_to_x11_button(axis, value),
+			WL_POINTER_BUTTON_STATE_RELEASED);
+}
+
+static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) {
+	// Who cares
+}
+
+static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
+		uint32_t axis_source) {
+	// Who cares
+}
+
+static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
+		uint32_t time, uint32_t axis) {
+	// Who cares
+}
+
+static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
+		uint32_t axis, int32_t discrete) {
+	// Who cares
+}
+
+struct wl_pointer_listener pointer_listener = {
+	.enter = wl_pointer_enter,
+	.leave = wl_pointer_leave,
+	.motion = wl_pointer_motion,
+	.button = wl_pointer_button,
+	.axis = wl_pointer_axis,
+	.frame = wl_pointer_frame,
+	.axis_source = wl_pointer_axis_source,
+	.axis_stop = wl_pointer_axis_stop,
+	.axis_discrete = wl_pointer_axis_discrete,
+};
+
+static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
+		enum wl_seat_capability caps) {
+	struct swaybar *bar = data;
+	if (bar->pointer.pointer != NULL) {
+		wl_pointer_release(bar->pointer.pointer);
+		bar->pointer.pointer = NULL;
+	}
+	if ((caps & WL_SEAT_CAPABILITY_POINTER)) {
+		bar->pointer.pointer = wl_seat_get_pointer(wl_seat);
+		wl_pointer_add_listener(bar->pointer.pointer, &pointer_listener, bar);
+	}
+}
+
+static void seat_handle_name(void *data, struct wl_seat *wl_seat,
+		const char *name) {
+	// Who cares
+}
+
+const struct wl_seat_listener seat_listener = {
+	.capabilities = seat_handle_capabilities,
+	.name = seat_handle_name,
+};
diff --git a/swaybar/meson.build b/swaybar/meson.build
index 0c1161723..c27cf2c2f 100644
--- a/swaybar/meson.build
+++ b/swaybar/meson.build
@@ -3,6 +3,7 @@ executable(
 		'bar.c',
 		'config.c',
 		'i3bar.c',
+		'input.c',
 		'ipc.c',
 		'main.c',
 		'render.c',