summaryrefslogtreecommitdiffstats
path: root/sway/input/input-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/input/input-manager.c')
-rw-r--r--sway/input/input-manager.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
new file mode 100644
index 00000000..52da8f5e
--- /dev/null
+++ b/sway/input/input-manager.c
@@ -0,0 +1,304 @@
1#define _XOPEN_SOURCE 700
2#include <ctype.h>
3#include <float.h>
4#include <limits.h>
5#include <stdio.h>
6#include <string.h>
7#include <libinput.h>
8#include <math.h>
9#include "sway/config.h"
10#include "sway/input/input-manager.h"
11#include "sway/input/seat.h"
12#include "sway/server.h"
13#include "stringop.h"
14#include "list.h"
15#include "log.h"
16
17static const char *default_seat = "seat0";
18
19// TODO make me not global
20struct sway_input_manager *input_manager;
21
22struct input_config *current_input_config = NULL;
23struct seat_config *current_seat_config = NULL;
24
25static struct sway_seat *input_manager_get_seat(
26 struct sway_input_manager *input, const char *seat_name) {
27 struct sway_seat *seat = NULL;
28 wl_list_for_each(seat, &input->seats, link) {
29 if (strcmp(seat->wlr_seat->name, seat_name) == 0) {
30 return seat;
31 }
32 }
33
34 return sway_seat_create(input, seat_name);
35}
36
37static inline int strlen_num(int num) {
38 if (num == 0) {
39 return 2;
40 }
41 return (int)((ceil(log10(abs(num)))+2));
42}
43
44static char *get_device_identifier(struct wlr_input_device *device) {
45 int vendor = device->vendor;
46 int product = device->product;
47 char *name = strdup(device->name);
48 name = strip_whitespace(name);
49
50 char *p = name;
51 for (; *p; ++p) {
52 if (*p == ' ') {
53 *p = '_';
54 }
55 }
56
57 int len =
58 (strlen(name) +
59 strlen_num(device->vendor) +
60 strlen_num(device->product) +
61 3) * sizeof(char);
62
63 char *identifier = malloc(len);
64 if (!identifier) {
65 sway_log(L_ERROR, "Unable to allocate unique input device name");
66 return NULL;
67 }
68
69 const char *fmt = "%d:%d:%s";
70 snprintf(identifier, len, fmt, vendor, product, name);
71 free(name);
72 return identifier;
73}
74
75static struct sway_input_device *input_sway_device_from_wlr(
76 struct sway_input_manager *input, struct wlr_input_device *device) {
77 struct sway_input_device *input_device = NULL;
78 wl_list_for_each(input_device, &input->devices, link) {
79 if (input_device->wlr_device == device) {
80 return input_device;
81 }
82 }
83 return NULL;
84}
85
86static bool input_has_seat_configuration(struct sway_input_manager *input) {
87 struct sway_seat *seat = NULL;
88 wl_list_for_each(seat, &input->seats, link) {
89 if (seat->config) {
90 return true;
91 }
92 }
93
94 return false;
95}
96
97static void input_add_notify(struct wl_listener *listener, void *data) {
98 struct sway_input_manager *input =
99 wl_container_of(listener, input, input_add);
100 struct wlr_input_device *device = data;
101
102 struct sway_input_device *input_device =
103 calloc(1, sizeof(struct sway_input_device));
104 if (!sway_assert(input_device, "could not allocate input device")) {
105 return;
106 }
107
108 input_device->wlr_device = device;
109 input_device->identifier = get_device_identifier(device);
110 wl_list_insert(&input->devices, &input_device->link);
111
112 sway_log(L_DEBUG, "adding device: '%s'",
113 input_device->identifier);
114
115 // find config
116 for (int i = 0; i < config->input_configs->length; ++i) {
117 struct input_config *input_config = config->input_configs->items[i];
118 if (strcmp(input_config->identifier, input_device->identifier) == 0) {
119 input_device->config = input_config;
120 break;
121 }
122 }
123
124 struct sway_seat *seat = NULL;
125 if (!input_has_seat_configuration(input)) {
126 sway_log(L_DEBUG, "no seat configuration, using default seat");
127 seat = input_manager_get_seat(input, default_seat);
128 sway_seat_add_device(seat, input_device);
129 return;
130 }
131
132 bool added = false;
133 wl_list_for_each(seat, &input->seats, link) {
134 if (seat->config &&
135 (seat_config_get_attachment(seat->config,
136 input_device->identifier) ||
137 seat_config_get_attachment(seat->config, "*"))) {
138 sway_seat_add_device(seat, input_device);
139 added = true;
140 }
141 }
142
143 if (!added) {
144 wl_list_for_each(seat, &input->seats, link) {
145 if (seat->config && seat->config->fallback == 1) {
146 sway_seat_add_device(seat, input_device);
147 added = true;
148 }
149 }
150 }
151
152 if (!added) {
153 sway_log(L_DEBUG,
154 "device '%s' is not configured on any seats",
155 input_device->identifier);
156 }
157}
158
159static void input_remove_notify(struct wl_listener *listener, void *data) {
160 struct sway_input_manager *input =
161 wl_container_of(listener, input, input_remove);
162 struct wlr_input_device *device = data;
163
164 struct sway_input_device *input_device =
165 input_sway_device_from_wlr(input, device);
166
167 if (!sway_assert(input_device, "could not find sway device")) {
168 return;
169 }
170
171 sway_log(L_DEBUG, "removing device: '%s'",
172 input_device->identifier);
173
174 struct sway_seat *seat = NULL;
175 wl_list_for_each(seat, &input->seats, link) {
176 sway_seat_remove_device(seat, input_device);
177 }
178
179 wl_list_remove(&input_device->link);
180 free(input_device->identifier);
181 free(input_device);
182}
183
184struct sway_input_manager *sway_input_manager_create(
185 struct sway_server *server) {
186 struct sway_input_manager *input =
187 calloc(1, sizeof(struct sway_input_manager));
188 if (!input) {
189 return NULL;
190 }
191 input->server = server;
192
193 wl_list_init(&input->devices);
194 wl_list_init(&input->seats);
195
196 // create the default seat
197 input_manager_get_seat(input, default_seat);
198
199 input->input_add.notify = input_add_notify;
200 wl_signal_add(&server->backend->events.input_add, &input->input_add);
201
202 input->input_remove.notify = input_remove_notify;
203 wl_signal_add(&server->backend->events.input_remove, &input->input_remove);
204
205 return input;
206}
207
208bool sway_input_manager_has_focus(struct sway_input_manager *input,
209 swayc_t *container) {
210 struct sway_seat *seat = NULL;
211 wl_list_for_each(seat, &input->seats, link) {
212 if (seat->focus == container) {
213 return true;
214 }
215 }
216
217 return false;
218}
219
220void sway_input_manager_set_focus(struct sway_input_manager *input,
221 swayc_t *container) {
222 struct sway_seat *seat ;
223 wl_list_for_each(seat, &input->seats, link) {
224 sway_seat_set_focus(seat, container);
225 }
226}
227
228void sway_input_manager_apply_input_config(struct sway_input_manager *input,
229 struct input_config *input_config) {
230 struct sway_input_device *input_device = NULL;
231 wl_list_for_each(input_device, &input->devices, link) {
232 if (strcmp(input_device->identifier, input_config->identifier) == 0) {
233 input_device->config = input_config;
234
235 struct sway_seat *seat = NULL;
236 wl_list_for_each(seat, &input->seats, link) {
237 sway_seat_configure_device(seat, input_device);
238 }
239 }
240 }
241}
242
243void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
244 struct seat_config *seat_config) {
245 sway_log(L_DEBUG, "applying new seat config for seat %s",
246 seat_config->name);
247 struct sway_seat *seat = input_manager_get_seat(input, seat_config->name);
248 if (!seat) {
249 return;
250 }
251
252 sway_seat_set_config(seat, seat_config);
253
254 // for every device, try to add it to a seat and if no seat has it
255 // attached, add it to the fallback seats.
256 struct sway_input_device *input_device = NULL;
257 wl_list_for_each(input_device, &input->devices, link) {
258 list_t *seat_list = create_list();
259 struct sway_seat *seat = NULL;
260 wl_list_for_each(seat, &input->seats, link) {
261 if (!seat->config) {
262 continue;
263 }
264 if (seat_config_get_attachment(seat->config, "*") ||
265 seat_config_get_attachment(seat->config,
266 input_device->identifier)) {
267 list_add(seat_list, seat);
268 }
269 }
270
271 if (seat_list->length) {
272 wl_list_for_each(seat, &input->seats, link) {
273 bool attached = false;
274 for (int i = 0; i < seat_list->length; ++i) {
275 if (seat == seat_list->items[i]) {
276 attached = true;
277 break;
278 }
279 }
280 if (attached) {
281 sway_seat_add_device(seat, input_device);
282 } else {
283 sway_seat_remove_device(seat, input_device);
284 }
285 }
286 } else {
287 wl_list_for_each(seat, &input->seats, link) {
288 if (seat->config && seat->config->fallback == 1) {
289 sway_seat_add_device(seat, input_device);
290 } else {
291 sway_seat_remove_device(seat, input_device);
292 }
293 }
294 }
295 list_free(seat_list);
296 }
297}
298
299void sway_input_manager_configure_xcursor(struct sway_input_manager *input) {
300 struct sway_seat *seat = NULL;
301 wl_list_for_each(seat, &input->seats, link) {
302 sway_seat_configure_xcursor(seat);
303 }
304}