aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h15
-rw-r--r--include/sway/config.h33
-rw-r--r--include/sway/container.h8
-rw-r--r--include/sway/input/cursor.h30
-rw-r--r--include/sway/input/input-manager.h49
-rw-r--r--include/sway/input/keyboard.h18
-rw-r--r--include/sway/input/seat.h47
-rw-r--r--include/sway/server.h2
-rw-r--r--meson.build1
-rw-r--r--sway/commands.c104
-rw-r--r--sway/commands/input.c55
-rw-r--r--sway/commands/input/accel_profile.c29
-rw-r--r--sway/commands/input/click_method.c34
-rw-r--r--sway/commands/input/drag_lock.c29
-rw-r--r--sway/commands/input/dwt.c28
-rw-r--r--sway/commands/input/events.c35
-rw-r--r--sway/commands/input/left_handed.c29
-rw-r--r--sway/commands/input/middle_emulation.c30
-rw-r--r--sway/commands/input/natural_scroll.c29
-rw-r--r--sway/commands/input/pointer_accel.c27
-rw-r--r--sway/commands/input/scroll_method.c33
-rw-r--r--sway/commands/input/tap.c32
-rw-r--r--sway/commands/input/xkb_layout.c24
-rw-r--r--sway/commands/input/xkb_model.c24
-rw-r--r--sway/commands/input/xkb_options.c24
-rw-r--r--sway/commands/input/xkb_rules.c24
-rw-r--r--sway/commands/input/xkb_variant.c24
-rw-r--r--sway/commands/seat.c35
-rw-r--r--sway/commands/seat/attach.c26
-rw-r--r--sway/config.c274
-rw-r--r--sway/desktop/output.c26
-rw-r--r--sway/desktop/wl_shell.c4
-rw-r--r--sway/desktop/xdg_shell_v6.c4
-rw-r--r--sway/desktop/xwayland.c3
-rw-r--r--sway/input/cursor.c184
-rw-r--r--sway/input/input-manager.c266
-rw-r--r--sway/input/input.c77
-rw-r--r--sway/input/keyboard.c111
-rw-r--r--sway/input/seat.c242
-rw-r--r--sway/main.c4
-rw-r--r--sway/meson.build25
-rw-r--r--sway/server.c4
-rw-r--r--sway/tree/container.c67
43 files changed, 2045 insertions, 124 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index b1f0423d..61950d0d 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -1,6 +1,8 @@
1#ifndef _SWAY_COMMANDS_H 1#ifndef _SWAY_COMMANDS_H
2#define _SWAY_COMMANDS_H 2#define _SWAY_COMMANDS_H
3 3
4#include "config.h"
5
4/** 6/**
5 * Indicates the result of a command's execution. 7 * Indicates the result of a command's execution.
6 */ 8 */
@@ -15,6 +17,7 @@ enum cmd_status {
15 CMD_BLOCK_BAR, 17 CMD_BLOCK_BAR,
16 CMD_BLOCK_BAR_COLORS, 18 CMD_BLOCK_BAR_COLORS,
17 CMD_BLOCK_INPUT, 19 CMD_BLOCK_INPUT,
20 CMD_BLOCK_SEAT,
18 CMD_BLOCK_COMMANDS, 21 CMD_BLOCK_COMMANDS,
19 CMD_BLOCK_IPC, 22 CMD_BLOCK_IPC,
20 CMD_BLOCK_IPC_EVENTS, 23 CMD_BLOCK_IPC_EVENTS,
@@ -39,6 +42,9 @@ enum expected_args {
39 EXPECTED_EQUAL_TO 42 EXPECTED_EQUAL_TO
40}; 43};
41 44
45void input_cmd_apply(struct input_config *input);
46void seat_cmd_apply(struct seat_config *seat);
47
42struct cmd_results *checkarg(int argc, const char *name, 48struct cmd_results *checkarg(int argc, const char *name,
43 enum expected_args type, int val); 49 enum expected_args type, int val);
44 50
@@ -107,6 +113,7 @@ sway_cmd cmd_gaps;
107sway_cmd cmd_hide_edge_borders; 113sway_cmd cmd_hide_edge_borders;
108sway_cmd cmd_include; 114sway_cmd cmd_include;
109sway_cmd cmd_input; 115sway_cmd cmd_input;
116sway_cmd cmd_seat;
110sway_cmd cmd_ipc; 117sway_cmd cmd_ipc;
111sway_cmd cmd_kill; 118sway_cmd cmd_kill;
112sway_cmd cmd_layout; 119sway_cmd cmd_layout;
@@ -176,6 +183,7 @@ sway_cmd bar_colors_cmd_statusline;
176sway_cmd bar_colors_cmd_focused_statusline; 183sway_cmd bar_colors_cmd_focused_statusline;
177sway_cmd bar_colors_cmd_urgent_workspace; 184sway_cmd bar_colors_cmd_urgent_workspace;
178 185
186sway_cmd input_cmd_seat;
179sway_cmd input_cmd_accel_profile; 187sway_cmd input_cmd_accel_profile;
180sway_cmd input_cmd_click_method; 188sway_cmd input_cmd_click_method;
181sway_cmd input_cmd_drag_lock; 189sway_cmd input_cmd_drag_lock;
@@ -187,6 +195,13 @@ sway_cmd input_cmd_natural_scroll;
187sway_cmd input_cmd_pointer_accel; 195sway_cmd input_cmd_pointer_accel;
188sway_cmd input_cmd_scroll_method; 196sway_cmd input_cmd_scroll_method;
189sway_cmd input_cmd_tap; 197sway_cmd input_cmd_tap;
198sway_cmd input_cmd_xkb_layout;
199sway_cmd input_cmd_xkb_model;
200sway_cmd input_cmd_xkb_options;
201sway_cmd input_cmd_xkb_rules;
202sway_cmd input_cmd_xkb_variant;
203
204sway_cmd seat_cmd_attach;
190 205
191sway_cmd cmd_ipc_cmd; 206sway_cmd cmd_ipc_cmd;
192sway_cmd cmd_ipc_events; 207sway_cmd cmd_ipc_events;
diff --git a/include/sway/config.h b/include/sway/config.h
index 139d7800..777fb5a8 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -67,11 +67,33 @@ struct input_config {
67 int send_events; 67 int send_events;
68 int tap; 68 int tap;
69 69
70 char *xkb_layout;
71 char *xkb_model;
72 char *xkb_options;
73 char *xkb_rules;
74 char *xkb_variant;
75
70 bool capturable; 76 bool capturable;
71 struct wlr_box region; 77 struct wlr_box region;
72}; 78};
73 79
74/** 80/**
81 * Options for misc device configurations that happen in the seat block
82 */
83struct seat_attachment_config {
84 char *identifier;
85 // TODO other things are configured here for some reason
86};
87
88/**
89 * Options for multiseat and other misc device configurations
90 */
91struct seat_config {
92 char *name;
93 list_t *attachments; // list of seat_attachment configs
94};
95
96/**
75 * Size and position configuration for a particular output. 97 * Size and position configuration for a particular output.
76 * 98 *
77 * This is set via the `output` command. 99 * This is set via the `output` command.
@@ -262,6 +284,7 @@ struct sway_config {
262 list_t *pid_workspaces; 284 list_t *pid_workspaces;
263 list_t *output_configs; 285 list_t *output_configs;
264 list_t *input_configs; 286 list_t *input_configs;
287 list_t *seat_configs;
265 list_t *criteria; 288 list_t *criteria;
266 list_t *no_focus; 289 list_t *no_focus;
267 list_t *active_bar_modifiers; 290 list_t *active_bar_modifiers;
@@ -358,10 +381,18 @@ char *do_var_replacement(char *str);
358struct cmd_results *check_security_config(); 381struct cmd_results *check_security_config();
359 382
360int input_identifier_cmp(const void *item, const void *data); 383int input_identifier_cmp(const void *item, const void *data);
384struct input_config *new_input_config(const char* identifier);
361void merge_input_config(struct input_config *dst, struct input_config *src); 385void merge_input_config(struct input_config *dst, struct input_config *src);
362void apply_input_config(struct input_config *ic, struct libinput_device *dev);
363void free_input_config(struct input_config *ic); 386void free_input_config(struct input_config *ic);
364 387
388int seat_name_cmp(const void *item, const void *data);
389struct seat_config *new_seat_config(const char* name);
390void merge_seat_config(struct seat_config *dst, struct seat_config *src);
391void free_seat_config(struct seat_config *ic);
392struct seat_attachment_config *seat_attachment_config_new();
393struct seat_attachment_config *seat_config_get_attachment(
394 struct seat_config *seat_config, char *identifier);
395
365int output_name_cmp(const void *item, const void *data); 396int output_name_cmp(const void *item, const void *data);
366struct output_config *new_output_config(); 397struct output_config *new_output_config();
367void merge_output_config(struct output_config *dst, struct output_config *src); 398void merge_output_config(struct output_config *dst, struct output_config *src);
diff --git a/include/sway/container.h b/include/sway/container.h
index b15e0428..9a5e312b 100644
--- a/include/sway/container.h
+++ b/include/sway/container.h
@@ -3,6 +3,7 @@
3#include <stdint.h> 3#include <stdint.h>
4#include <sys/types.h> 4#include <sys/types.h>
5#include <wlr/types/wlr_box.h> 5#include <wlr/types/wlr_box.h>
6#include <wlr/types/wlr_surface.h>
6#include "list.h" 7#include "list.h"
7 8
8typedef struct sway_container swayc_t; 9typedef struct sway_container swayc_t;
@@ -123,6 +124,10 @@ struct sway_container {
123 * Marks applied to the container, list_t of char*. 124 * Marks applied to the container, list_t of char*.
124 */ 125 */
125 list_t *marks; 126 list_t *marks;
127
128 struct {
129 struct wl_signal destroy;
130 } events;
126}; 131};
127 132
128void swayc_descendants_of_type(swayc_t *root, enum swayc_types type, 133void swayc_descendants_of_type(swayc_t *root, enum swayc_types type,
@@ -137,4 +142,7 @@ swayc_t *destroy_view(swayc_t *view);
137 142
138swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type); 143swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type);
139 144
145swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
146 struct wlr_surface **surface, double *sx, double *sy);
147
140#endif 148#endif
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h
new file mode 100644
index 00000000..cc529de6
--- /dev/null
+++ b/include/sway/input/cursor.h
@@ -0,0 +1,30 @@
1#ifndef _SWAY_CURSOR_H
2#define _SWAY_CURSOR_H
3
4#include "sway/input/seat.h"
5
6struct sway_cursor {
7 struct sway_seat *seat;
8 struct wlr_cursor *cursor;
9 struct wlr_xcursor_manager *xcursor_manager;
10
11 double x, y;
12
13 struct wl_listener motion;
14 struct wl_listener motion_absolute;
15 struct wl_listener button;
16 struct wl_listener axis;
17
18 struct wl_listener touch_down;
19 struct wl_listener touch_up;
20 struct wl_listener touch_motion;
21
22 struct wl_listener tool_axis;
23 struct wl_listener tool_tip;
24
25 struct wl_listener request_set_cursor;
26};
27
28struct sway_cursor *sway_cursor_create(struct sway_seat *seat);
29
30#endif
diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h
new file mode 100644
index 00000000..cdcffab6
--- /dev/null
+++ b/include/sway/input/input-manager.h
@@ -0,0 +1,49 @@
1#ifndef _SWAY_INPUT_MANAGER_H
2#define _SWAY_INPUT_MANAGER_H
3#include <libinput.h>
4#include "sway/server.h"
5#include "sway/config.h"
6#include "list.h"
7
8extern struct input_config *current_input_config;
9extern struct seat_config *current_seat_config;
10
11/**
12 * The global singleton input manager
13 * TODO: make me not a global
14 */
15extern struct sway_input_manager *input_manager;
16
17struct sway_input_device {
18 char *identifier;
19 struct wlr_input_device *wlr_device;
20 struct input_config *config;
21 struct wl_list link;
22};
23
24struct sway_input_manager {
25 struct wl_listener input_add;
26 struct wl_listener input_remove;
27 struct sway_server *server;
28 struct wl_list devices;
29 struct wl_list seats;
30};
31
32struct sway_input_manager *sway_input_manager_create(
33 struct sway_server *server);
34
35bool sway_input_manager_has_focus(struct sway_input_manager *input,
36 swayc_t *container);
37
38void sway_input_manager_set_focus(struct sway_input_manager *input,
39 swayc_t *container);
40
41void sway_input_manager_configure_xcursor(struct sway_input_manager *input);
42
43void sway_input_manager_apply_input_config(struct sway_input_manager *input,
44 struct input_config *input_config);
45
46void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
47 struct seat_config *seat_config);
48
49#endif
diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h
new file mode 100644
index 00000000..89cde3fa
--- /dev/null
+++ b/include/sway/input/keyboard.h
@@ -0,0 +1,18 @@
1#include "sway/input/seat.h"
2
3struct sway_keyboard {
4 struct sway_seat_device *seat_device;
5 struct wl_list link; // sway_seat::keyboards
6
7 struct xkb_keymap *keymap;
8
9 struct wl_listener keyboard_key;
10 struct wl_listener keyboard_modifiers;
11};
12
13struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
14 struct sway_seat_device *device);
15
16void sway_keyboard_configure(struct sway_keyboard *keyboard);
17
18void sway_keyboard_destroy(struct sway_keyboard *keyboard);
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
new file mode 100644
index 00000000..db69f83e
--- /dev/null
+++ b/include/sway/input/seat.h
@@ -0,0 +1,47 @@
1#ifndef _SWAY_SEAT_H
2#define _SWAY_SEAT_H
3
4#include <wlr/types/wlr_seat.h>
5#include "sway/input/input-manager.h"
6
7struct sway_seat_device {
8 struct sway_seat *sway_seat;
9 struct sway_input_device *input_device;
10 struct sway_keyboard *keyboard;
11 struct seat_attachment_config *attachment_config;
12 struct wl_list link; // sway_seat::devices
13};
14
15struct sway_seat {
16 struct wlr_seat *wlr_seat;
17 struct seat_config *config;
18 struct sway_cursor *cursor;
19 struct sway_input_manager *input;
20 swayc_t *focus;
21
22 struct wl_listener focus_destroy;
23
24 struct wl_list devices; // sway_seat_device::link
25
26 struct wl_list link; // input_manager::seats
27};
28
29struct sway_seat *sway_seat_create(struct sway_input_manager *input,
30 const char *seat_name);
31
32void sway_seat_add_device(struct sway_seat *seat,
33 struct sway_input_device *device);
34
35void sway_seat_configure_device(struct sway_seat *seat,
36 struct sway_input_device *device);
37
38void sway_seat_remove_device(struct sway_seat *seat,
39 struct sway_input_device *device);
40
41void sway_seat_configure_xcursor(struct sway_seat *seat);
42
43void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container);
44
45void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config);
46
47#endif
diff --git a/include/sway/server.h b/include/sway/server.h
index 3fa72e84..76a05476 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -22,7 +22,7 @@ struct sway_server {
22 struct wlr_compositor *compositor; 22 struct wlr_compositor *compositor;
23 struct wlr_data_device_manager *data_device_manager; 23 struct wlr_data_device_manager *data_device_manager;
24 24
25 struct sway_input *input; 25 struct sway_input_manager *input;
26 26
27 struct wl_listener output_add; 27 struct wl_listener output_add;
28 struct wl_listener output_remove; 28 struct wl_listener output_remove;
diff --git a/meson.build b/meson.build
index 8e7b98ed..029aea46 100644
--- a/meson.build
+++ b/meson.build
@@ -29,6 +29,7 @@ xkbcommon = dependency('xkbcommon')
29pango = dependency('pango') 29pango = dependency('pango')
30pixman = dependency('pixman-1') 30pixman = dependency('pixman-1')
31libcap = dependency('libcap') 31libcap = dependency('libcap')
32libinput = dependency('libinput')
32math = cc.find_library('m') 33math = cc.find_library('m')
33git = find_program('git', required: false) 34git = find_program('git', required: false)
34a2x = find_program('a2x', required: false) 35a2x = find_program('a2x', required: false)
diff --git a/sway/commands.c b/sway/commands.c
index d6cf7a64..7485f2f6 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -9,6 +9,7 @@
9#include "sway/commands.h" 9#include "sway/commands.h"
10#include "sway/config.h" 10#include "sway/config.h"
11#include "sway/security.h" 11#include "sway/security.h"
12#include "sway/input/input-manager.h"
12#include "stringop.h" 13#include "stringop.h"
13#include "log.h" 14#include "log.h"
14 15
@@ -56,6 +57,40 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type
56 return error; 57 return error;
57} 58}
58 59
60void input_cmd_apply(struct input_config *input) {
61 int i;
62 i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier);
63 if (i >= 0) {
64 // merge existing config
65 struct input_config *ic = config->input_configs->items[i];
66 merge_input_config(ic, input);
67 free_input_config(input);
68 input = ic;
69 } else {
70 list_add(config->input_configs, input);
71 }
72
73 current_input_config = input;
74 sway_input_manager_apply_input_config(input_manager, input);
75}
76
77void seat_cmd_apply(struct seat_config *seat) {
78 int i;
79 i = list_seq_find(config->seat_configs, seat_name_cmp, seat->name);
80 if (i >= 0) {
81 // merge existing config
82 struct seat_config *sc = config->seat_configs->items[i];
83 merge_seat_config(sc, seat);
84 free_seat_config(seat);
85 seat = sc;
86 } else {
87 list_add(config->seat_configs, seat);
88 }
89
90 current_seat_config = seat;
91 sway_input_manager_apply_seat_config(input_manager, seat);
92}
93
59/** 94/**
60 * Check and add color to buffer. 95 * Check and add color to buffer.
61 * 96 *
@@ -96,7 +131,9 @@ static struct cmd_handler handlers[] = {
96 { "exec_always", cmd_exec_always }, 131 { "exec_always", cmd_exec_always },
97 { "exit", cmd_exit }, 132 { "exit", cmd_exit },
98 { "include", cmd_include }, 133 { "include", cmd_include },
134 { "input", cmd_input },
99 { "output", cmd_output }, 135 { "output", cmd_output },
136 { "seat", cmd_seat },
100}; 137};
101 138
102static int handler_compare(const void *_a, const void *_b) { 139static int handler_compare(const void *_a, const void *_b) {
@@ -105,37 +142,50 @@ static int handler_compare(const void *_a, const void *_b) {
105 return strcasecmp(a->command, b->command); 142 return strcasecmp(a->command, b->command);
106} 143}
107 144
145// must be in order for the bsearch
146static struct cmd_handler input_handlers[] = {
147 { "accel_profile", input_cmd_accel_profile },
148 { "click_method", input_cmd_click_method },
149 { "drag_lock", input_cmd_drag_lock },
150 { "dwt", input_cmd_dwt },
151 { "events", input_cmd_events },
152 { "left_handed", input_cmd_left_handed },
153 { "middle_emulation", input_cmd_middle_emulation },
154 { "natural_scroll", input_cmd_natural_scroll },
155 { "pointer_accel", input_cmd_pointer_accel },
156 { "scroll_method", input_cmd_scroll_method },
157 { "tap", input_cmd_tap },
158 { "xkb_layout", input_cmd_xkb_layout },
159 { "xkb_model", input_cmd_xkb_model },
160 { "xkb_options", input_cmd_xkb_options },
161 { "xkb_rules", input_cmd_xkb_rules },
162 { "xkb_variant", input_cmd_xkb_variant },
163};
164
165// must be in order for the bsearch
166static struct cmd_handler seat_handlers[] = {
167 { "attach", seat_cmd_attach },
168};
169
108static struct cmd_handler *find_handler(char *line, enum cmd_status block) { 170static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
109 struct cmd_handler d = { .command=line }; 171 struct cmd_handler d = { .command=line };
110 struct cmd_handler *res = NULL; 172 struct cmd_handler *res = NULL;
111 sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT); 173 sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT);
112 /* TODO 174
113 if (block == CMD_BLOCK_BAR) { 175 if (block == CMD_BLOCK_INPUT) {
114 res = bsearch(&d, bar_handlers,
115 sizeof(bar_handlers) / sizeof(struct cmd_handler),
116 sizeof(struct cmd_handler), handler_compare);
117 } else if (block == CMD_BLOCK_BAR_COLORS){
118 res = bsearch(&d, bar_colors_handlers,
119 sizeof(bar_colors_handlers) / sizeof(struct cmd_handler),
120 sizeof(struct cmd_handler), handler_compare);
121 } else if (block == CMD_BLOCK_INPUT) {
122 res = bsearch(&d, input_handlers, 176 res = bsearch(&d, input_handlers,
123 sizeof(input_handlers) / sizeof(struct cmd_handler), 177 sizeof(input_handlers) / sizeof(struct cmd_handler),
124 sizeof(struct cmd_handler), handler_compare); 178 sizeof(struct cmd_handler), handler_compare);
125 } else if (block == CMD_BLOCK_IPC) { 179 } else if (block == CMD_BLOCK_SEAT) {
126 res = bsearch(&d, ipc_handlers, 180 res = bsearch(&d, seat_handlers,
127 sizeof(ipc_handlers) / sizeof(struct cmd_handler), 181 sizeof(seat_handlers) / sizeof(struct cmd_handler),
128 sizeof(struct cmd_handler), handler_compare); 182 sizeof(struct cmd_handler), handler_compare);
129 } else if (block == CMD_BLOCK_IPC_EVENTS) {
130 res = bsearch(&d, ipc_event_handlers,
131 sizeof(ipc_event_handlers) / sizeof(struct cmd_handler),
132 sizeof(struct cmd_handler), handler_compare);
133 } else { 183 } else {
134 */
135 res = bsearch(&d, handlers, 184 res = bsearch(&d, handlers,
136 sizeof(handlers) / sizeof(struct cmd_handler), 185 sizeof(handlers) / sizeof(struct cmd_handler),
137 sizeof(struct cmd_handler), handler_compare); 186 sizeof(struct cmd_handler), handler_compare);
138 //} 187 }
188
139 return res; 189 return res;
140} 190}
141 191
@@ -239,8 +289,8 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) {
239 argv[i] = do_var_replacement(argv[i]); 289 argv[i] = do_var_replacement(argv[i]);
240 unescape_string(argv[i]); 290 unescape_string(argv[i]);
241 } 291 }
242 /* Strip quotes for first argument. 292 // Strip quotes for first argument.
243 * TODO This part needs to be handled much better */ 293 // TODO This part needs to be handled much better
244 if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { 294 if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
245 strip_quotes(argv[1]); 295 strip_quotes(argv[1]);
246 } 296 }
diff --git a/sway/commands/input.c b/sway/commands/input.c
new file mode 100644
index 00000000..5ca9c2e6
--- /dev/null
+++ b/sway/commands/input.c
@@ -0,0 +1,55 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *cmd_input(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) {
10 return error;
11 }
12
13 if (config->reading && strcmp("{", argv[1]) == 0) {
14 current_input_config = new_input_config(argv[0]);
15 sway_log(L_DEBUG, "entering input block: %s", current_input_config->identifier);
16 return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL);
17 }
18
19 if (argc > 2) {
20 int argc_new = argc-2;
21 char **argv_new = argv+2;
22
23 struct cmd_results *res;
24 current_input_config = new_input_config(argv[0]);
25 if (strcasecmp("accel_profile", argv[1]) == 0) {
26 res = input_cmd_accel_profile(argc_new, argv_new);
27 } else if (strcasecmp("click_method", argv[1]) == 0) {
28 res = input_cmd_click_method(argc_new, argv_new);
29 } else if (strcasecmp("drag_lock", argv[1]) == 0) {
30 res = input_cmd_drag_lock(argc_new, argv_new);
31 } else if (strcasecmp("dwt", argv[1]) == 0) {
32 res = input_cmd_dwt(argc_new, argv_new);
33 } else if (strcasecmp("events", argv[1]) == 0) {
34 res = input_cmd_events(argc_new, argv_new);
35 } else if (strcasecmp("left_handed", argv[1]) == 0) {
36 res = input_cmd_left_handed(argc_new, argv_new);
37 } else if (strcasecmp("middle_emulation", argv[1]) == 0) {
38 res = input_cmd_middle_emulation(argc_new, argv_new);
39 } else if (strcasecmp("natural_scroll", argv[1]) == 0) {
40 res = input_cmd_natural_scroll(argc_new, argv_new);
41 } else if (strcasecmp("pointer_accel", argv[1]) == 0) {
42 res = input_cmd_pointer_accel(argc_new, argv_new);
43 } else if (strcasecmp("scroll_method", argv[1]) == 0) {
44 res = input_cmd_scroll_method(argc_new, argv_new);
45 } else if (strcasecmp("tap", argv[1]) == 0) {
46 res = input_cmd_tap(argc_new, argv_new);
47 } else {
48 res = cmd_results_new(CMD_INVALID, "input <device>", "Unknown command %s", argv[1]);
49 }
50 current_input_config = NULL;
51 return res;
52 }
53
54 return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL);
55}
diff --git a/sway/commands/input/accel_profile.c b/sway/commands/input/accel_profile.c
new file mode 100644
index 00000000..9b5fb7a2
--- /dev/null
+++ b/sway/commands/input/accel_profile.c
@@ -0,0 +1,29 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5
6struct cmd_results *input_cmd_accel_profile(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11 if (!current_input_config) {
12 return cmd_results_new(CMD_FAILURE, "accel_profile",
13 "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 if (strcasecmp(argv[0], "adaptive") == 0) {
19 new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
20 } else if (strcasecmp(argv[0], "flat") == 0) {
21 new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
22 } else {
23 return cmd_results_new(CMD_INVALID, "accel_profile",
24 "Expected 'accel_profile <adaptive|flat>'");
25 }
26
27 input_cmd_apply(new_config);
28 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
29}
diff --git a/sway/commands/input/click_method.c b/sway/commands/input/click_method.c
new file mode 100644
index 00000000..a0e3bddf
--- /dev/null
+++ b/sway/commands/input/click_method.c
@@ -0,0 +1,34 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *input_cmd_click_method(int argc, char **argv) {
8 sway_log(L_DEBUG, "click_method for device: %d %s",
9 current_input_config==NULL, current_input_config->identifier);
10 struct cmd_results *error = NULL;
11 if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) {
12 return error;
13 }
14 if (!current_input_config) {
15 return cmd_results_new(CMD_FAILURE, "click_method",
16 "No input device defined.");
17 }
18 struct input_config *new_config =
19 new_input_config(current_input_config->identifier);
20
21 if (strcasecmp(argv[0], "none") == 0) {
22 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
23 } else if (strcasecmp(argv[0], "button_areas") == 0) {
24 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
25 } else if (strcasecmp(argv[0], "clickfinger") == 0) {
26 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
27 } else {
28 return cmd_results_new(CMD_INVALID, "click_method",
29 "Expected 'click_method <none|button_areas|clickfinger'");
30 }
31
32 input_cmd_apply(new_config);
33 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
34}
diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c
new file mode 100644
index 00000000..149a6183
--- /dev/null
+++ b/sway/commands/input/drag_lock.c
@@ -0,0 +1,29 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5
6struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11 if (!current_input_config) {
12 return cmd_results_new(CMD_FAILURE,
13 "drag_lock", "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 if (strcasecmp(argv[0], "enabled") == 0) {
19 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
20 } else if (strcasecmp(argv[0], "disabled") == 0) {
21 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
22 } else {
23 return cmd_results_new(CMD_INVALID, "drag_lock",
24 "Expected 'drag_lock <enabled|disabled>'");
25 }
26
27 input_cmd_apply(new_config);
28 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
29}
diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c
new file mode 100644
index 00000000..0954575c
--- /dev/null
+++ b/sway/commands/input/dwt.c
@@ -0,0 +1,28 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5
6struct cmd_results *input_cmd_dwt(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11 if (!current_input_config) {
12 return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined.");
13 }
14 struct input_config *new_config =
15 new_input_config(current_input_config->identifier);
16
17 if (strcasecmp(argv[0], "enabled") == 0) {
18 new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
19 } else if (strcasecmp(argv[0], "disabled") == 0) {
20 new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
21 } else {
22 return cmd_results_new(CMD_INVALID, "dwt",
23 "Expected 'dwt <enabled|disabled>'");
24 }
25
26 input_cmd_apply(new_config);
27 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
28}
diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c
new file mode 100644
index 00000000..f44c0ec7
--- /dev/null
+++ b/sway/commands/input/events.c
@@ -0,0 +1,35 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *input_cmd_events(int argc, char **argv) {
8 sway_log(L_DEBUG, "events for device: %s",
9 current_input_config->identifier);
10 struct cmd_results *error = NULL;
11 if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) {
12 return error;
13 }
14 if (!current_input_config) {
15 return cmd_results_new(CMD_FAILURE, "events",
16 "No input device defined.");
17 }
18 struct input_config *new_config =
19 new_input_config(current_input_config->identifier);
20
21 if (strcasecmp(argv[0], "enabled") == 0) {
22 new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
23 } else if (strcasecmp(argv[0], "disabled") == 0) {
24 new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
25 } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) {
26 new_config->send_events =
27 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
28 } else {
29 return cmd_results_new(CMD_INVALID, "events",
30 "Expected 'events <enabled|disabled|disabled_on_external_mouse>'");
31 }
32
33 input_cmd_apply(new_config);
34 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
35}
diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c
new file mode 100644
index 00000000..dc8fcd56
--- /dev/null
+++ b/sway/commands/input/left_handed.c
@@ -0,0 +1,29 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5
6struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11 if (!current_input_config) {
12 return cmd_results_new(CMD_FAILURE, "left_handed",
13 "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 if (strcasecmp(argv[0], "enabled") == 0) {
19 new_config->left_handed = 1;
20 } else if (strcasecmp(argv[0], "disabled") == 0) {
21 new_config->left_handed = 0;
22 } else {
23 return cmd_results_new(CMD_INVALID, "left_handed",
24 "Expected 'left_handed <enabled|disabled>'");
25 }
26
27 input_cmd_apply(new_config);
28 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
29}
diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c
new file mode 100644
index 00000000..e19964d8
--- /dev/null
+++ b/sway/commands/input/middle_emulation.c
@@ -0,0 +1,30 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5
6struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11 if (!current_input_config) {
12 return cmd_results_new(CMD_FAILURE, "middle_emulation",
13 "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 if (strcasecmp(argv[0], "enabled") == 0) {
19 new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
20 } else if (strcasecmp(argv[0], "disabled") == 0) {
21 new_config->middle_emulation =
22 LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
23 } else {
24 return cmd_results_new(CMD_INVALID, "middle_emulation",
25 "Expected 'middle_emulation <enabled|disabled>'");
26 }
27
28 input_cmd_apply(new_config);
29 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
30}
diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c
new file mode 100644
index 00000000..8272c5b3
--- /dev/null
+++ b/sway/commands/input/natural_scroll.c
@@ -0,0 +1,29 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5
6struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11 if (!current_input_config) {
12 return cmd_results_new(CMD_FAILURE, "natural_scoll",
13 "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 if (strcasecmp(argv[0], "enabled") == 0) {
19 new_config->natural_scroll = 1;
20 } else if (strcasecmp(argv[0], "disabled") == 0) {
21 new_config->natural_scroll = 0;
22 } else {
23 return cmd_results_new(CMD_INVALID, "natural_scroll",
24 "Expected 'natural_scroll <enabled|disabled>'");
25 }
26
27 input_cmd_apply(new_config);
28 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
29}
diff --git a/sway/commands/input/pointer_accel.c b/sway/commands/input/pointer_accel.c
new file mode 100644
index 00000000..2c9db5bf
--- /dev/null
+++ b/sway/commands/input/pointer_accel.c
@@ -0,0 +1,27 @@
1#include <stdlib.h>
2#include <string.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5
6struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11 if (!current_input_config) {
12 return cmd_results_new(CMD_FAILURE,
13 "pointer_accel", "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 float pointer_accel = atof(argv[0]);
19 if (pointer_accel < -1 || pointer_accel > 1) {
20 return cmd_results_new(CMD_INVALID, "pointer_accel",
21 "Input out of range [-1, 1]");
22 }
23 new_config->pointer_accel = pointer_accel;
24
25 input_cmd_apply(new_config);
26 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
27}
diff --git a/sway/commands/input/scroll_method.c b/sway/commands/input/scroll_method.c
new file mode 100644
index 00000000..40277155
--- /dev/null
+++ b/sway/commands/input/scroll_method.c
@@ -0,0 +1,33 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5
6struct cmd_results *input_cmd_scroll_method(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11 if (!current_input_config) {
12 return cmd_results_new(CMD_FAILURE, "scroll_method",
13 "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 if (strcasecmp(argv[0], "none") == 0) {
19 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
20 } else if (strcasecmp(argv[0], "two_finger") == 0) {
21 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
22 } else if (strcasecmp(argv[0], "edge") == 0) {
23 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
24 } else if (strcasecmp(argv[0], "on_button_down") == 0) {
25 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
26 } else {
27 return cmd_results_new(CMD_INVALID, "scroll_method",
28 "Expected 'scroll_method <none|two_finger|edge|on_button_down>'");
29 }
30
31 input_cmd_apply(new_config);
32 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
33}
diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c
new file mode 100644
index 00000000..18a54087
--- /dev/null
+++ b/sway/commands/input/tap.c
@@ -0,0 +1,32 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *input_cmd_tap(int argc, char **argv) {
8 sway_log(L_DEBUG, "tap for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) {
11 return error;
12 }
13 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "tap", "No input device defined.");
15 }
16 struct input_config *new_config =
17 new_input_config(current_input_config->identifier);
18
19 if (strcasecmp(argv[0], "enabled") == 0) {
20 new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED;
21 } else if (strcasecmp(argv[0], "disabled") == 0) {
22 new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
23 } else {
24 return cmd_results_new(CMD_INVALID, "tap",
25 "Expected 'tap <enabled|disabled>'");
26 }
27
28 sway_log(L_DEBUG, "apply-tap for device: %s",
29 current_input_config->identifier);
30 input_cmd_apply(new_config);
31 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
32}
diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c
new file mode 100644
index 00000000..9a9ce044
--- /dev/null
+++ b/sway/commands/input/xkb_layout.c
@@ -0,0 +1,24 @@
1#define _XOPEN_SOURCE 700
2#include "sway/commands.h"
3#include "sway/input/input-manager.h"
4#include "log.h"
5
6struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) {
7 sway_log(L_DEBUG, "xkb layout for device: %s", current_input_config->identifier);
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "xkb_layout", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "xkb_layout", "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 new_config->xkb_layout = strdup(argv[0]);
19
20 sway_log(L_DEBUG, "apply-xkb_layout for device: %s",
21 current_input_config->identifier);
22 input_cmd_apply(new_config);
23 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
24}
diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c
new file mode 100644
index 00000000..14a50ffb
--- /dev/null
+++ b/sway/commands/input/xkb_model.c
@@ -0,0 +1,24 @@
1#define _XOPEN_SOURCE 700
2#include "sway/commands.h"
3#include "sway/input/input-manager.h"
4#include "log.h"
5
6struct cmd_results *input_cmd_xkb_model(int argc, char **argv) {
7 sway_log(L_DEBUG, "xkb model for device: %s", current_input_config->identifier);
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "xkb_model", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "xkb_model", "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 new_config->xkb_model = strdup(argv[0]);
19
20 sway_log(L_DEBUG, "apply-xkb_model for device: %s",
21 current_input_config->identifier);
22 input_cmd_apply(new_config);
23 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
24}
diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c
new file mode 100644
index 00000000..67eb5342
--- /dev/null
+++ b/sway/commands/input/xkb_options.c
@@ -0,0 +1,24 @@
1#define _XOPEN_SOURCE 700
2#include "sway/commands.h"
3#include "sway/input/input-manager.h"
4#include "log.h"
5
6struct cmd_results *input_cmd_xkb_options(int argc, char **argv) {
7 sway_log(L_DEBUG, "xkb options for device: %s", current_input_config->identifier);
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "xkb_options", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "xkb_options", "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 new_config->xkb_options = strdup(argv[0]);
19
20 sway_log(L_DEBUG, "apply-xkb_options for device: %s",
21 current_input_config->identifier);
22 input_cmd_apply(new_config);
23 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
24}
diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c
new file mode 100644
index 00000000..3eda0bdd
--- /dev/null
+++ b/sway/commands/input/xkb_rules.c
@@ -0,0 +1,24 @@
1#define _XOPEN_SOURCE 700
2#include "sway/commands.h"
3#include "sway/input/input-manager.h"
4#include "log.h"
5
6struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) {
7 sway_log(L_DEBUG, "xkb rules for device: %s", current_input_config->identifier);
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "xkb_rules", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "xkb_rules", "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 new_config->xkb_rules = strdup(argv[0]);
19
20 sway_log(L_DEBUG, "apply-xkb_rules for device: %s",
21 current_input_config->identifier);
22 input_cmd_apply(new_config);
23 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
24}
diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c
new file mode 100644
index 00000000..c7f93ad4
--- /dev/null
+++ b/sway/commands/input/xkb_variant.c
@@ -0,0 +1,24 @@
1#define _XOPEN_SOURCE 700
2#include "sway/commands.h"
3#include "sway/input/input-manager.h"
4#include "log.h"
5
6struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) {
7 sway_log(L_DEBUG, "xkb variant for device: %s", current_input_config->identifier);
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "xkb_variant", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "xkb_variant", "No input device defined.");
14 }
15 struct input_config *new_config =
16 new_input_config(current_input_config->identifier);
17
18 new_config->xkb_variant = strdup(argv[0]);
19
20 sway_log(L_DEBUG, "apply-xkb_variant for device: %s",
21 current_input_config->identifier);
22 input_cmd_apply(new_config);
23 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
24}
diff --git a/sway/commands/seat.c b/sway/commands/seat.c
new file mode 100644
index 00000000..4f9e259b
--- /dev/null
+++ b/sway/commands/seat.c
@@ -0,0 +1,35 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *cmd_seat(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 2))) {
10 return error;
11 }
12
13 if (config->reading && strcmp("{", argv[1]) == 0) {
14 current_seat_config = new_seat_config(argv[0]);
15 sway_log(L_DEBUG, "entering seat block: %s", current_seat_config->name);
16 return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL);
17 }
18
19 if (argc > 2) {
20 int argc_new = argc-2;
21 char **argv_new = argv+2;
22
23 struct cmd_results *res;
24 current_seat_config = new_seat_config(argv[0]);
25 if (strcasecmp("attach", argv[1]) == 0) {
26 res = seat_cmd_attach(argc_new, argv_new);
27 } else {
28 res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]);
29 }
30 current_seat_config = NULL;
31 return res;
32 }
33
34 return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL);
35}
diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c
new file mode 100644
index 00000000..996c1bda
--- /dev/null
+++ b/sway/commands/seat/attach.c
@@ -0,0 +1,26 @@
1#define _XOPEN_SOURCE 700
2#include <string.h>
3#include <strings.h>
4#include "sway/input/input-manager.h"
5#include "sway/commands.h"
6#include "sway/config.h"
7#include "log.h"
8#include "stringop.h"
9
10struct cmd_results *seat_cmd_attach(int argc, char **argv) {
11 struct cmd_results *error = NULL;
12 if ((error = checkarg(argc, "attach", EXPECTED_AT_LEAST, 1))) {
13 return error;
14 }
15 if (!current_seat_config) {
16 return cmd_results_new(CMD_FAILURE, "attach", "No seat defined");
17 }
18
19 struct seat_config *new_config = new_seat_config(current_seat_config->name);
20 struct seat_attachment_config *new_attachment = seat_attachment_config_new();
21 new_attachment->identifier = strdup(argv[0]);
22 list_add(new_config->attachments, new_attachment);
23
24 seat_cmd_apply(new_config);
25 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
26}
diff --git a/sway/config.c b/sway/config.c
index 61131845..4e34aa8c 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -21,6 +21,7 @@
21#include <dev/evdev/input-event-codes.h> 21#include <dev/evdev/input-event-codes.h>
22#endif 22#endif
23#include <wlr/types/wlr_output.h> 23#include <wlr/types/wlr_output.h>
24#include "sway/input/input-manager.h"
24#include "sway/commands.h" 25#include "sway/commands.h"
25#include "sway/config.h" 26#include "sway/config.h"
26#include "sway/layout.h" 27#include "sway/layout.h"
@@ -44,11 +45,13 @@ static void config_defaults(struct sway_config *config) {
44 if (!(config->criteria = create_list())) goto cleanup; 45 if (!(config->criteria = create_list())) goto cleanup;
45 if (!(config->no_focus = create_list())) goto cleanup; 46 if (!(config->no_focus = create_list())) goto cleanup;
46 if (!(config->input_configs = create_list())) goto cleanup; 47 if (!(config->input_configs = create_list())) goto cleanup;
48 if (!(config->seat_configs = create_list())) goto cleanup;
47 if (!(config->output_configs = create_list())) goto cleanup; 49 if (!(config->output_configs = create_list())) goto cleanup;
48 50
49 if (!(config->cmd_queue = create_list())) goto cleanup; 51 if (!(config->cmd_queue = create_list())) goto cleanup;
50 52
51 if (!(config->current_mode = malloc(sizeof(struct sway_mode)))) goto cleanup; 53 if (!(config->current_mode = malloc(sizeof(struct sway_mode))))
54 goto cleanup;
52 if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; 55 if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup;
53 strcpy(config->current_mode->name, "default"); 56 strcpy(config->current_mode->name, "default");
54 if (!(config->current_mode->bindings = create_list())) goto cleanup; 57 if (!(config->current_mode->bindings = create_list())) goto cleanup;
@@ -226,6 +229,227 @@ static int qstrcmp(const void* a, const void* b) {
226 return strcmp(*((char**) a), *((char**) b)); 229 return strcmp(*((char**) a), *((char**) b));
227} 230}
228 231
232struct input_config *new_input_config(const char* identifier) {
233 struct input_config *input = calloc(1, sizeof(struct input_config));
234 if (!input) {
235 sway_log(L_DEBUG, "Unable to allocate input config");
236 return NULL;
237 }
238 sway_log(L_DEBUG, "new_input_config(%s)", identifier);
239 if (!(input->identifier = strdup(identifier))) {
240 free(input);
241 sway_log(L_DEBUG, "Unable to allocate input config");
242 return NULL;
243 }
244
245 input->tap = INT_MIN;
246 input->drag_lock = INT_MIN;
247 input->dwt = INT_MIN;
248 input->send_events = INT_MIN;
249 input->click_method = INT_MIN;
250 input->middle_emulation = INT_MIN;
251 input->natural_scroll = INT_MIN;
252 input->accel_profile = INT_MIN;
253 input->pointer_accel = FLT_MIN;
254 input->scroll_method = INT_MIN;
255 input->left_handed = INT_MIN;
256
257 return input;
258}
259
260void merge_input_config(struct input_config *dst, struct input_config *src) {
261 if (src->identifier) {
262 free(dst->identifier);
263 dst->identifier = strdup(src->identifier);
264 }
265 if (src->accel_profile != INT_MIN) {
266 dst->accel_profile = src->accel_profile;
267 }
268 if (src->click_method != INT_MIN) {
269 dst->click_method = src->click_method;
270 }
271 if (src->drag_lock != INT_MIN) {
272 dst->drag_lock = src->drag_lock;
273 }
274 if (src->dwt != INT_MIN) {
275 dst->dwt = src->dwt;
276 }
277 if (src->middle_emulation != INT_MIN) {
278 dst->middle_emulation = src->middle_emulation;
279 }
280 if (src->natural_scroll != INT_MIN) {
281 dst->natural_scroll = src->natural_scroll;
282 }
283 if (src->pointer_accel != FLT_MIN) {
284 dst->pointer_accel = src->pointer_accel;
285 }
286 if (src->scroll_method != INT_MIN) {
287 dst->scroll_method = src->scroll_method;
288 }
289 if (src->send_events != INT_MIN) {
290 dst->send_events = src->send_events;
291 }
292 if (src->tap != INT_MIN) {
293 dst->tap = src->tap;
294 }
295 if (src->xkb_layout) {
296 free(dst->xkb_layout);
297 dst->xkb_layout = strdup(src->xkb_layout);
298 }
299 if (src->xkb_model) {
300 free(dst->xkb_model);
301 dst->xkb_model = strdup(src->xkb_model);
302 }
303 if (src->xkb_options) {
304 free(dst->xkb_options);
305 dst->xkb_options = strdup(src->xkb_options);
306 }
307 if (src->xkb_rules) {
308 free(dst->xkb_rules);
309 dst->xkb_rules = strdup(src->xkb_rules);
310 }
311 if (src->xkb_variant) {
312 free(dst->xkb_variant);
313 dst->xkb_variant = strdup(src->xkb_variant);
314 }
315}
316
317void free_input_config(struct input_config *ic) {
318 if (!ic) {
319 return;
320 }
321 free(ic->identifier);
322 free(ic);
323}
324
325int input_identifier_cmp(const void *item, const void *data) {
326 const struct input_config *ic = item;
327 const char *identifier = data;
328 return strcmp(ic->identifier, identifier);
329}
330
331struct seat_config *new_seat_config(const char* name) {
332 struct seat_config *seat = calloc(1, sizeof(struct seat_config));
333 if (!seat) {
334 sway_log(L_DEBUG, "Unable to allocate seat config");
335 return NULL;
336 }
337
338 sway_log(L_DEBUG, "new_seat_config(%s)", name);
339 seat->name = strdup(name);
340 if (!sway_assert(seat->name, "could not allocate name for seat")) {
341 return NULL;
342 }
343
344 seat->attachments = create_list();
345 if (!sway_assert(seat->attachments,
346 "could not allocate seat attachments list")) {
347 return NULL;
348 }
349
350 return seat;
351}
352
353struct seat_attachment_config *seat_attachment_config_new() {
354 struct seat_attachment_config *attachment =
355 calloc(1, sizeof(struct seat_attachment_config));
356 if (!attachment) {
357 sway_log(L_DEBUG, "cannot allocate attachment config");
358 return NULL;
359 }
360 return attachment;
361}
362
363static void seat_attachment_config_free(
364 struct seat_attachment_config *attachment) {
365 free(attachment->identifier);
366 free(attachment);
367 return;
368}
369
370static struct seat_attachment_config *seat_attachment_config_copy(
371 struct seat_attachment_config *attachment) {
372 struct seat_attachment_config *copy = seat_attachment_config_new();
373 if (!copy) {
374 return NULL;
375 }
376
377 copy->identifier = strdup(attachment->identifier);
378
379 return copy;
380}
381
382static void merge_seat_attachment_config(struct seat_attachment_config *dest,
383 struct seat_attachment_config *source) {
384 // nothing to merge yet, but there will be some day
385}
386
387void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
388 if (source->name) {
389 free(dest->name);
390 dest->name = strdup(source->name);
391 }
392
393 for (int i = 0; i < source->attachments->length; ++i) {
394 struct seat_attachment_config *source_attachment =
395 source->attachments->items[i];
396 bool found = false;
397 for (int j = 0; j < dest->attachments->length; ++j) {
398 struct seat_attachment_config *dest_attachment =
399 dest->attachments->items[j];
400 if (strcmp(source_attachment->identifier,
401 dest_attachment->identifier) == 0) {
402 merge_seat_attachment_config(dest_attachment,
403 source_attachment);
404 found = true;
405 }
406 }
407
408 if (!found) {
409 struct seat_attachment_config *copy =
410 seat_attachment_config_copy(source_attachment);
411 if (copy) {
412 list_add(dest->attachments, copy);
413 }
414 }
415 }
416}
417
418void free_seat_config(struct seat_config *seat) {
419 if (!seat) {
420 return;
421 }
422
423 free(seat->name);
424 for (int i = 0; i < seat->attachments->length; ++i) {
425 struct seat_attachment_config *attachment =
426 seat->attachments->items[i];
427 seat_attachment_config_free(attachment);
428 }
429
430 list_free(seat->attachments);
431 free(seat);
432}
433
434int seat_name_cmp(const void *item, const void *data) {
435 const struct seat_config *sc = item;
436 const char *name = data;
437 return strcmp(sc->name, name);
438}
439
440struct seat_attachment_config *seat_config_get_attachment(
441 struct seat_config *seat_config, char *identifier) {
442 for (int i = 0; i < seat_config->attachments->length; ++i) {
443 struct seat_attachment_config *attachment =
444 seat_config->attachments->items[i];
445 if (strcmp(attachment->identifier, identifier) == 0) {
446 return attachment;
447 }
448 }
449
450 return NULL;
451}
452
229bool load_main_config(const char *file, bool is_active) { 453bool load_main_config(const char *file, bool is_active) {
230 char *path; 454 char *path;
231 if (file != NULL) { 455 if (file != NULL) {
@@ -256,8 +480,9 @@ bool load_main_config(const char *file, bool is_active) {
256 bool success = true; 480 bool success = true;
257 DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); 481 DIR *dir = opendir(SYSCONFDIR "/sway/security.d");
258 if (!dir) { 482 if (!dir) {
259 sway_log(L_ERROR, "%s does not exist, sway will have no security configuration" 483 sway_log(L_ERROR,
260 " and will probably be broken", SYSCONFDIR "/sway/security.d"); 484 "%s does not exist, sway will have no security configuration"
485 " and will probably be broken", SYSCONFDIR "/sway/security.d");
261 } else { 486 } else {
262 list_t *secconfigs = create_list(); 487 list_t *secconfigs = create_list();
263 char *base = SYSCONFDIR "/sway/security.d/"; 488 char *base = SYSCONFDIR "/sway/security.d/";
@@ -281,8 +506,12 @@ bool load_main_config(const char *file, bool is_active) {
281 list_qsort(secconfigs, qstrcmp); 506 list_qsort(secconfigs, qstrcmp);
282 for (int i = 0; i < secconfigs->length; ++i) { 507 for (int i = 0; i < secconfigs->length; ++i) {
283 char *_path = secconfigs->items[i]; 508 char *_path = secconfigs->items[i];
284 if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && (s.st_mode & 0777) != 0444)) { 509 if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 ||
285 sway_log(L_ERROR, "Refusing to load %s - it must be owned by root and mode 644 or 444", _path); 510 (((s.st_mode & 0777) != 0644) &&
511 (s.st_mode & 0777) != 0444)) {
512 sway_log(L_ERROR,
513 "Refusing to load %s - it must be owned by root "
514 "and mode 644 or 444", _path);
286 success = false; 515 success = false;
287 } else { 516 } else {
288 success = success && load_config(_path, config); 517 success = success && load_config(_path, config);
@@ -311,7 +540,8 @@ bool load_main_config(const char *file, bool is_active) {
311 return success; 540 return success;
312} 541}
313 542
314static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { 543static bool load_include_config(const char *path, const char *parent_dir,
544 struct sway_config *config) {
315 // save parent config 545 // save parent config
316 const char *parent_config = config->current_config; 546 const char *parent_config = config->current_config;
317 547
@@ -321,7 +551,8 @@ static bool load_include_config(const char *path, const char *parent_dir, struct
321 len = len + strlen(parent_dir) + 2; 551 len = len + strlen(parent_dir) + 2;
322 full_path = malloc(len * sizeof(char)); 552 full_path = malloc(len * sizeof(char));
323 if (!full_path) { 553 if (!full_path) {
324 sway_log(L_ERROR, "Unable to allocate full path to included config"); 554 sway_log(L_ERROR,
555 "Unable to allocate full path to included config");
325 return false; 556 return false;
326 } 557 }
327 snprintf(full_path, len, "%s/%s", parent_dir, path); 558 snprintf(full_path, len, "%s/%s", parent_dir, path);
@@ -340,7 +571,9 @@ static bool load_include_config(const char *path, const char *parent_dir, struct
340 for (j = 0; j < config->config_chain->length; ++j) { 571 for (j = 0; j < config->config_chain->length; ++j) {
341 char *old_path = config->config_chain->items[j]; 572 char *old_path = config->config_chain->items[j];
342 if (strcmp(real_path, old_path) == 0) { 573 if (strcmp(real_path, old_path) == 0) {
343 sway_log(L_DEBUG, "%s already included once, won't be included again.", real_path); 574 sway_log(L_DEBUG,
575 "%s already included once, won't be included again.",
576 real_path);
344 free(real_path); 577 free(real_path);
345 return false; 578 return false;
346 } 579 }
@@ -400,6 +633,7 @@ bool load_include_configs(const char *path, struct sway_config *config) {
400 return true; 633 return true;
401} 634}
402 635
636
403bool read_config(FILE *file, struct sway_config *config) { 637bool read_config(FILE *file, struct sway_config *config) {
404 bool success = true; 638 bool success = true;
405 enum cmd_status block = CMD_BLOCK_END; 639 enum cmd_status block = CMD_BLOCK_END;
@@ -427,8 +661,8 @@ bool read_config(FILE *file, struct sway_config *config) {
427 switch(res->status) { 661 switch(res->status) {
428 case CMD_FAILURE: 662 case CMD_FAILURE:
429 case CMD_INVALID: 663 case CMD_INVALID:
430 sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, line, 664 sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number,
431 res->error, config->current_config); 665 line, res->error, config->current_config);
432 success = false; 666 success = false;
433 break; 667 break;
434 668
@@ -453,6 +687,14 @@ bool read_config(FILE *file, struct sway_config *config) {
453 } 687 }
454 break; 688 break;
455 689
690 case CMD_BLOCK_SEAT:
691 if (block == CMD_BLOCK_END) {
692 block = CMD_BLOCK_SEAT;
693 } else {
694 sway_log(L_ERROR, "Invalid block '%s'", line);
695 }
696 break;
697
456 case CMD_BLOCK_BAR: 698 case CMD_BLOCK_BAR:
457 if (block == CMD_BLOCK_END) { 699 if (block == CMD_BLOCK_END) {
458 block = CMD_BLOCK_BAR; 700 block = CMD_BLOCK_BAR;
@@ -503,8 +745,13 @@ bool read_config(FILE *file, struct sway_config *config) {
503 745
504 case CMD_BLOCK_INPUT: 746 case CMD_BLOCK_INPUT:
505 sway_log(L_DEBUG, "End of input block"); 747 sway_log(L_DEBUG, "End of input block");
506 // TODO: input 748 current_input_config = NULL;
507 //current_input_config = NULL; 749 block = CMD_BLOCK_END;
750 break;
751
752 case CMD_BLOCK_SEAT:
753 sway_log(L_DEBUG, "End of seat block");
754 current_seat_config = NULL;
508 block = CMD_BLOCK_END; 755 block = CMD_BLOCK_END;
509 break; 756 break;
510 757
@@ -569,7 +816,8 @@ char *do_var_replacement(char *str) {
569 char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); 816 char *newstr = malloc(strlen(str) - vnlen + vvlen + 1);
570 if (!newstr) { 817 if (!newstr) {
571 sway_log(L_ERROR, 818 sway_log(L_ERROR,
572 "Unable to allocate replacement during variable expansion"); 819 "Unable to allocate replacement "
820 "during variable expansion");
573 break; 821 break;
574 } 822 }
575 char *newptr = newstr; 823 char *newptr = newstr;
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index ad843b31..3b87c2e7 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -12,6 +12,8 @@
12#include "sway/output.h" 12#include "sway/output.h"
13#include "sway/server.h" 13#include "sway/server.h"
14#include "sway/view.h" 14#include "sway/view.h"
15#include "sway/input/input-manager.h"
16#include "sway/input/seat.h"
15 17
16static void output_frame_view(swayc_t *view, void *data) { 18static void output_frame_view(swayc_t *view, void *data) {
17 struct sway_output *output = data; 19 struct sway_output *output = data;
@@ -23,8 +25,8 @@ static void output_frame_view(swayc_t *view, void *data) {
23 } 25 }
24 // TODO 26 // TODO
25 // - Deal with wlr_output_layout 27 // - Deal with wlr_output_layout
26 int width = sway_view->width; 28 int width = sway_view->surface->current->width;
27 int height = sway_view->height; 29 int height = sway_view->surface->current->height;
28 int render_width = width * wlr_output->scale; 30 int render_width = width * wlr_output->scale;
29 int render_height = height * wlr_output->scale; 31 int render_height = height * wlr_output->scale;
30 double ox = view->x, oy = view->y; 32 double ox = view->x, oy = view->y;
@@ -38,19 +40,33 @@ static void output_frame_view(swayc_t *view, void *data) {
38 // return; 40 // return;
39 //} 41 //}
40 42
43 // if the shell specifies window geometry, make the top left corner of the
44 // window in the top left corner of the container to avoid arbitrarily
45 // sized gaps based on the attached buffer size
46 int window_offset_x = 0;
47 int window_offset_y = 0;
48
49 if (view->sway_view->type == SWAY_XDG_SHELL_V6_VIEW) {
50 window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry->x;
51 window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry->y;
52 }
53
41 // TODO 54 // TODO
42 double rotation = 0; 55 double rotation = 0;
43 float matrix[16]; 56 float matrix[16];
44 57
45 float translate_origin[16]; 58 float translate_origin[16];
46 wlr_matrix_translate(&translate_origin, 59 wlr_matrix_translate(&translate_origin,
47 (int)ox + render_width / 2, (int)oy + render_height / 2, 0); 60 (int)ox + render_width / 2 - window_offset_x,
61 (int)oy + render_height / 2 - window_offset_y,
62 0);
48 63
49 float rotate[16]; 64 float rotate[16];
50 wlr_matrix_rotate(&rotate, rotation); 65 wlr_matrix_rotate(&rotate, rotation);
51 66
52 float translate_center[16]; 67 float translate_center[16];
53 wlr_matrix_translate(&translate_center, -render_width / 2, 68 wlr_matrix_translate(&translate_center,
69 -render_width / 2,
54 -render_height / 2, 0); 70 -render_height / 2, 0);
55 71
56 float scale[16]; 72 float scale[16];
@@ -115,6 +131,8 @@ void output_add_notify(struct wl_listener *listener, void *data) {
115 return; 131 return;
116 } 132 }
117 133
134 sway_input_manager_configure_xcursor(input_manager);
135
118 output->frame.notify = output_frame_notify; 136 output->frame.notify = output_frame_notify;
119 wl_signal_add(&wlr_output->events.frame, &output->frame); 137 wl_signal_add(&wlr_output->events.frame, &output->frame);
120} 138}
diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c
index 3f5a358a..df81d5be 100644
--- a/sway/desktop/wl_shell.c
+++ b/sway/desktop/wl_shell.c
@@ -7,6 +7,8 @@
7#include "sway/layout.h" 7#include "sway/layout.h"
8#include "sway/server.h" 8#include "sway/server.h"
9#include "sway/view.h" 9#include "sway/view.h"
10#include "sway/input/seat.h"
11#include "sway/input/input-manager.h"
10#include "log.h" 12#include "log.h"
11 13
12static bool assert_wl_shell(struct sway_view *view) { 14static bool assert_wl_shell(struct sway_view *view) {
@@ -126,4 +128,6 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
126 sway_view->swayc = cont; 128 sway_view->swayc = cont;
127 129
128 arrange_windows(cont->parent, -1, -1); 130 arrange_windows(cont->parent, -1, -1);
131
132 sway_input_manager_set_focus(input_manager, cont);
129} 133}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 2435c256..82775e2f 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -7,6 +7,8 @@
7#include "sway/layout.h" 7#include "sway/layout.h"
8#include "sway/server.h" 8#include "sway/server.h"
9#include "sway/view.h" 9#include "sway/view.h"
10#include "sway/input/seat.h"
11#include "sway/input/input-manager.h"
10#include "log.h" 12#include "log.h"
11 13
12static bool assert_xdg(struct sway_view *view) { 14static bool assert_xdg(struct sway_view *view) {
@@ -132,4 +134,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
132 sway_view->swayc = cont; 134 sway_view->swayc = cont;
133 135
134 arrange_windows(cont->parent, -1, -1); 136 arrange_windows(cont->parent, -1, -1);
137
138 sway_input_manager_set_focus(input_manager, cont);
135} 139}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index e3799d2d..29bed955 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -10,6 +10,8 @@
10#include "sway/server.h" 10#include "sway/server.h"
11#include "sway/view.h" 11#include "sway/view.h"
12#include "sway/output.h" 12#include "sway/output.h"
13#include "sway/input/seat.h"
14#include "sway/input/input-manager.h"
13#include "log.h" 15#include "log.h"
14 16
15 static bool assert_xwayland(struct sway_view *view) { 17 static bool assert_xwayland(struct sway_view *view) {
@@ -171,4 +173,5 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
171 sway_view->swayc = cont; 173 sway_view->swayc = cont;
172 174
173 arrange_windows(cont->parent, -1, -1); 175 arrange_windows(cont->parent, -1, -1);
176 sway_input_manager_set_focus(input_manager, cont);
174} 177}
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
new file mode 100644
index 00000000..24d4642d
--- /dev/null
+++ b/sway/input/cursor.c
@@ -0,0 +1,184 @@
1#define _XOPEN_SOURCE 700
2#ifdef __linux__
3#include <linux/input-event-codes.h>
4#elif __FreeBSD__
5#include <dev/evdev/input-event-codes.h>
6#endif
7#include <wlr/types/wlr_cursor.h>
8#include <wlr/types/wlr_xcursor_manager.h>
9#include "sway/input/cursor.h"
10#include "sway/view.h"
11#include "list.h"
12#include "log.h"
13
14static void cursor_update_position(struct sway_cursor *cursor) {
15 double x = cursor->cursor->x;
16 double y = cursor->cursor->y;
17
18 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
19 "left_ptr", cursor->cursor);
20
21 cursor->x = x;
22 cursor->y = y;
23}
24
25static void cursor_send_pointer_motion(struct sway_cursor *cursor,
26 uint32_t time) {
27 struct wlr_seat *seat = cursor->seat->wlr_seat;
28 struct wlr_surface *surface = NULL;
29 double sx, sy;
30 swayc_t *swayc =
31 swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy);
32 if (swayc) {
33 wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
34 wlr_seat_pointer_notify_motion(seat, time, sx, sy);
35 } else {
36 wlr_seat_pointer_clear_focus(seat);
37 }
38}
39
40static void handle_cursor_motion(struct wl_listener *listener, void *data) {
41 struct sway_cursor *cursor =
42 wl_container_of(listener, cursor, motion);
43 struct wlr_event_pointer_motion *event = data;
44 wlr_cursor_move(cursor->cursor, event->device,
45 event->delta_x, event->delta_y);
46 cursor_update_position(cursor);
47 cursor_send_pointer_motion(cursor, event->time_msec);
48}
49
50static void handle_cursor_motion_absolute(struct wl_listener *listener,
51 void *data) {
52 struct sway_cursor *cursor =
53 wl_container_of(listener, cursor, motion_absolute);
54 struct wlr_event_pointer_motion_absolute *event = data;
55 wlr_cursor_warp_absolute(cursor->cursor, event->device,
56 event->x_mm / event->width_mm, event->y_mm / event->height_mm);
57 cursor_update_position(cursor);
58 cursor_send_pointer_motion(cursor, event->time_msec);
59}
60
61static void handle_cursor_button(struct wl_listener *listener, void *data) {
62 struct sway_cursor *cursor =
63 wl_container_of(listener, cursor, button);
64 struct wlr_event_pointer_button *event = data;
65
66 if (event->button == BTN_LEFT) {
67 struct wlr_surface *surface = NULL;
68 double sx, sy;
69 swayc_t *swayc =
70 swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy);
71
72 sway_seat_set_focus(cursor->seat, swayc);
73 }
74
75 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec,
76 event->button, event->state);
77}
78
79static void handle_cursor_axis(struct wl_listener *listener, void *data) {
80 struct sway_cursor *cursor =
81 wl_container_of(listener, cursor, axis);
82 struct wlr_event_pointer_axis *event = data;
83 wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
84 event->orientation, event->delta);
85}
86
87static void handle_touch_down(struct wl_listener *listener, void *data) {
88 struct sway_cursor *cursor =
89 wl_container_of(listener, cursor, touch_down);
90 struct wlr_event_touch_down *event = data;
91 sway_log(L_DEBUG, "TODO: handle touch down event: %p", event);
92}
93
94static void handle_touch_up(struct wl_listener *listener, void *data) {
95 struct sway_cursor *cursor =
96 wl_container_of(listener, cursor, touch_up);
97 struct wlr_event_touch_up *event = data;
98 sway_log(L_DEBUG, "TODO: handle touch up event: %p", event);
99}
100
101static void handle_touch_motion(struct wl_listener *listener, void *data) {
102 struct sway_cursor *cursor =
103 wl_container_of(listener, cursor, touch_motion);
104 struct wlr_event_touch_motion *event = data;
105 sway_log(L_DEBUG, "TODO: handle touch motion event: %p", event);
106}
107
108static void handle_tool_axis(struct wl_listener *listener, void *data) {
109 struct sway_cursor *cursor =
110 wl_container_of(listener, cursor, tool_axis);
111 struct wlr_event_tablet_tool_axis *event = data;
112 sway_log(L_DEBUG, "TODO: handle tool axis event: %p", event);
113}
114
115static void handle_tool_tip(struct wl_listener *listener, void *data) {
116 struct sway_cursor *cursor =
117 wl_container_of(listener, cursor, tool_tip);
118 struct wlr_event_tablet_tool_tip *event = data;
119 sway_log(L_DEBUG, "TODO: handle tool tip event: %p", event);
120}
121
122static void handle_request_set_cursor(struct wl_listener *listener,
123 void *data) {
124 struct sway_cursor *cursor =
125 wl_container_of(listener, cursor, request_set_cursor);
126 struct wlr_seat_pointer_request_set_cursor_event *event = data;
127 sway_log(L_DEBUG, "TODO: handle request set cursor event: %p", event);
128}
129
130struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
131 struct sway_cursor *cursor = calloc(1, sizeof(struct sway_cursor));
132 if (!sway_assert(cursor, "could not allocate sway cursor")) {
133 return NULL;
134 }
135
136 struct wlr_cursor *wlr_cursor = wlr_cursor_create();
137 if (!sway_assert(wlr_cursor, "could not allocate wlr cursor")) {
138 free(cursor);
139 return NULL;
140 }
141
142 cursor->seat = seat;
143 wlr_cursor_attach_output_layout(wlr_cursor,
144 root_container.sway_root->output_layout);
145
146 // input events
147 wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
148 cursor->motion.notify = handle_cursor_motion;
149
150 wl_signal_add(&wlr_cursor->events.motion_absolute,
151 &cursor->motion_absolute);
152 cursor->motion_absolute.notify = handle_cursor_motion_absolute;
153
154 wl_signal_add(&wlr_cursor->events.button, &cursor->button);
155 cursor->button.notify = handle_cursor_button;
156
157 wl_signal_add(&wlr_cursor->events.axis, &cursor->axis);
158 cursor->axis.notify = handle_cursor_axis;
159
160 wl_signal_add(&wlr_cursor->events.touch_down, &cursor->touch_down);
161 cursor->touch_down.notify = handle_touch_down;
162
163 wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up);
164 cursor->touch_up.notify = handle_touch_up;
165
166 wl_signal_add(&wlr_cursor->events.touch_motion,
167 &cursor->touch_motion);
168 cursor->touch_motion.notify = handle_touch_motion;
169
170 wl_signal_add(&wlr_cursor->events.tablet_tool_axis,
171 &cursor->tool_axis);
172 cursor->tool_axis.notify = handle_tool_axis;
173
174 wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip);
175 cursor->tool_tip.notify = handle_tool_tip;
176
177 wl_signal_add(&seat->wlr_seat->events.request_set_cursor,
178 &cursor->request_set_cursor);
179 cursor->request_set_cursor.notify = handle_request_set_cursor;
180
181 cursor->cursor = wlr_cursor;
182
183 return cursor;
184}
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
new file mode 100644
index 00000000..1950b6d9
--- /dev/null
+++ b/sway/input/input-manager.c
@@ -0,0 +1,266 @@
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 "sway/config.h"
9#include "sway/input/input-manager.h"
10#include "sway/input/seat.h"
11#include "sway/server.h"
12#include "list.h"
13#include "log.h"
14
15static const char *default_seat = "seat0";
16
17// TODO make me not global
18struct sway_input_manager *input_manager;
19
20struct input_config *current_input_config = NULL;
21struct seat_config *current_seat_config = NULL;
22
23static struct sway_seat *input_manager_get_seat(
24 struct sway_input_manager *input, const char *seat_name) {
25 struct sway_seat *seat = NULL;
26 wl_list_for_each(seat, &input->seats, link) {
27 if (strcmp(seat->wlr_seat->name, seat_name) == 0) {
28 return seat;
29 }
30 }
31
32 return sway_seat_create(input, seat_name);
33}
34
35static char *get_device_identifier(struct wlr_input_device *device) {
36 int vendor = device->vendor;
37 int product = device->product;
38 char *name = strdup(device->name);
39
40 char *p = name;
41 for (; *p; ++p) {
42 if (*p == ' ') {
43 *p = '_';
44 }
45 }
46
47 sway_log(L_DEBUG, "rewritten name %s", name);
48
49 int len = strlen(name) + sizeof(char) * 6;
50 char *identifier = malloc(len);
51 if (!identifier) {
52 sway_log(L_ERROR, "Unable to allocate unique input device name");
53 return NULL;
54 }
55
56 const char *fmt = "%d:%d:%s";
57 snprintf(identifier, len, fmt, vendor, product, name);
58 free(name);
59 return identifier;
60}
61
62static struct sway_input_device *input_sway_device_from_wlr(
63 struct sway_input_manager *input, struct wlr_input_device *device) {
64 struct sway_input_device *input_device = NULL;
65 wl_list_for_each(input_device, &input->devices, link) {
66 if (input_device->wlr_device == device) {
67 return input_device;
68 }
69 }
70 return NULL;
71}
72
73static struct sway_input_device *input_sway_device_from_config(
74 struct sway_input_manager *input, struct input_config *config) {
75 struct sway_input_device *input_device = NULL;
76 wl_list_for_each(input_device, &input->devices, link) {
77 if (strcmp(input_device->identifier, config->identifier) == 0) {
78 return input_device;
79 }
80 }
81 return NULL;
82}
83
84static struct sway_input_device *input_sway_device_from_identifier(
85 struct sway_input_manager *input, char *identifier) {
86 struct sway_input_device *input_device = NULL;
87 wl_list_for_each(input_device, &input->devices, link) {
88 if (strcmp(input_device->identifier, identifier) == 0) {
89 return input_device;
90 }
91 }
92 return NULL;
93}
94
95static bool input_has_seat_configuration(struct sway_input_manager *input) {
96 struct sway_seat *seat = NULL;
97 wl_list_for_each(seat, &input->seats, link) {
98 if (seat->config) {
99 return true;
100 }
101 }
102
103 return false;
104}
105
106static void input_add_notify(struct wl_listener *listener, void *data) {
107 struct sway_input_manager *input =
108 wl_container_of(listener, input, input_add);
109 struct wlr_input_device *device = data;
110
111 struct sway_input_device *input_device =
112 calloc(1, sizeof(struct sway_input_device));
113 if (!sway_assert(input_device, "could not allocate input device")) {
114 return;
115 }
116
117 input_device->wlr_device = device;
118 input_device->identifier = get_device_identifier(device);
119 wl_list_insert(&input->devices, &input_device->link);
120
121 // find config
122 for (int i = 0; i < config->input_configs->length; ++i) {
123 struct input_config *input_config = config->input_configs->items[i];
124 if (strcmp(input_config->identifier, input_device->identifier) == 0) {
125 input_device->config = input_config;
126 break;
127 }
128 }
129
130 struct sway_seat *seat = NULL;
131 if (!input_has_seat_configuration(input)) {
132 seat = input_manager_get_seat(input, default_seat);
133 sway_seat_add_device(seat, input_device);
134 return;
135 }
136
137 wl_list_for_each(seat, &input->seats, link) {
138 if (seat->config &&
139 (seat_config_get_attachment(seat->config, input_device->identifier) ||
140 seat_config_get_attachment(seat->config, "*"))) {
141 sway_seat_add_device(seat, input_device);
142 }
143 }
144}
145
146static void input_remove_notify(struct wl_listener *listener, void *data) {
147 struct sway_input_manager *input =
148 wl_container_of(listener, input, input_remove);
149 struct wlr_input_device *device = data;
150
151 struct sway_input_device *input_device =
152 input_sway_device_from_wlr(input, device);
153
154 if (!sway_assert(input_device, "could not find sway device")) {
155 return;
156 }
157
158 struct sway_seat *seat = NULL;
159 wl_list_for_each(seat, &input->seats, link) {
160 sway_seat_remove_device(seat, input_device);
161 }
162
163 wl_list_remove(&input_device->link);
164 free(input_device->identifier);
165 free(input_device);
166}
167
168struct sway_input_manager *sway_input_manager_create(
169 struct sway_server *server) {
170 struct sway_input_manager *input =
171 calloc(1, sizeof(struct sway_input_manager));
172 if (!input) {
173 return NULL;
174 }
175 input->server = server;
176
177 wl_list_init(&input->devices);
178 wl_list_init(&input->seats);
179
180 // create the default seat
181 input_manager_get_seat(input, default_seat);
182
183 input->input_add.notify = input_add_notify;
184 wl_signal_add(&server->backend->events.input_add, &input->input_add);
185
186 input->input_remove.notify = input_remove_notify;
187 wl_signal_add(&server->backend->events.input_remove, &input->input_remove);
188
189 return input;
190}
191
192bool sway_input_manager_has_focus(struct sway_input_manager *input,
193 swayc_t *container) {
194 struct sway_seat *seat = NULL;
195 wl_list_for_each(seat, &input->seats, link) {
196 if (seat->focus == container) {
197 return true;
198 }
199 }
200
201 return false;
202}
203
204void sway_input_manager_set_focus(struct sway_input_manager *input,
205 swayc_t *container) {
206 struct sway_seat *seat ;
207 wl_list_for_each(seat, &input->seats, link) {
208 sway_seat_set_focus(seat, container);
209 }
210}
211
212void sway_input_manager_apply_input_config(struct sway_input_manager *input,
213 struct input_config *input_config) {
214 struct sway_input_device *input_device =
215 input_sway_device_from_config(input, input_config);
216 if (!input_device) {
217 return;
218 }
219 input_device->config = input_config;
220
221 struct sway_seat *seat = NULL;
222 wl_list_for_each(seat, &input->seats, link) {
223 sway_seat_configure_device(seat, input_device);
224 }
225}
226
227void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
228 struct seat_config *seat_config) {
229 struct sway_seat *seat = input_manager_get_seat(input, seat_config->name);
230 // the old config is invalid so clear it
231 sway_seat_set_config(seat, NULL);
232
233 // clear devices
234 struct sway_input_device *input_device = NULL;
235 wl_list_for_each(input_device, &input->devices, link) {
236 sway_seat_remove_device(seat, input_device);
237 }
238
239 if (seat_config_get_attachment(seat_config, "*")) {
240 wl_list_for_each(input_device, &input->devices, link) {
241 sway_seat_add_device(seat, input_device);
242 }
243 } else {
244 for (int i = 0; i < seat_config->attachments->length; ++i) {
245 struct seat_attachment_config *attachment =
246 seat_config->attachments->items[i];
247
248 struct sway_input_device *device =
249 input_sway_device_from_identifier(input,
250 attachment->identifier);
251
252 if (device) {
253 sway_seat_add_device(seat, device);
254 }
255 }
256 }
257
258 sway_seat_set_config(seat, seat_config);
259}
260
261void sway_input_manager_configure_xcursor(struct sway_input_manager *input) {
262 struct sway_seat *seat = NULL;
263 wl_list_for_each(seat, &input->seats, link) {
264 sway_seat_configure_xcursor(seat);
265 }
266}
diff --git a/sway/input/input.c b/sway/input/input.c
deleted file mode 100644
index 02b4995e..00000000
--- a/sway/input/input.c
+++ /dev/null
@@ -1,77 +0,0 @@
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 "sway/config.h"
9#include "sway/input.h"
10#include "sway/server.h"
11#include "list.h"
12#include "log.h"
13
14struct input_config *current_input_config = NULL;
15
16struct sway_input *sway_input_create(struct sway_server *server) {
17 struct sway_input *input = calloc(1, sizeof(struct sway_input));
18 if (!input) {
19 return NULL;
20 }
21 return input;
22}
23
24struct input_config *new_input_config(const char* identifier) {
25 struct input_config *input = calloc(1, sizeof(struct input_config));
26 if (!input) {
27 sway_log(L_DEBUG, "Unable to allocate input config");
28 return NULL;
29 }
30 sway_log(L_DEBUG, "new_input_config(%s)", identifier);
31 if (!(input->identifier = strdup(identifier))) {
32 free(input);
33 sway_log(L_DEBUG, "Unable to allocate input config");
34 return NULL;
35 }
36
37 input->tap = INT_MIN;
38 input->drag_lock = INT_MIN;
39 input->dwt = INT_MIN;
40 input->send_events = INT_MIN;
41 input->click_method = INT_MIN;
42 input->middle_emulation = INT_MIN;
43 input->natural_scroll = INT_MIN;
44 input->accel_profile = INT_MIN;
45 input->pointer_accel = FLT_MIN;
46 input->scroll_method = INT_MIN;
47 input->left_handed = INT_MIN;
48
49 return input;
50}
51
52char *libinput_dev_unique_id(struct libinput_device *device) {
53 int vendor = libinput_device_get_id_vendor(device);
54 int product = libinput_device_get_id_product(device);
55 char *name = strdup(libinput_device_get_name(device));
56
57 char *p = name;
58 for (; *p; ++p) {
59 if (*p == ' ') {
60 *p = '_';
61 }
62 }
63
64 sway_log(L_DEBUG, "rewritten name %s", name);
65
66 int len = strlen(name) + sizeof(char) * 6;
67 char *identifier = malloc(len);
68 if (!identifier) {
69 sway_log(L_ERROR, "Unable to allocate unique input device name");
70 return NULL;
71 }
72
73 const char *fmt = "%d:%d:%s";
74 snprintf(identifier, len, fmt, vendor, product, name);
75 free(name);
76 return identifier;
77}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
new file mode 100644
index 00000000..b9b571a6
--- /dev/null
+++ b/sway/input/keyboard.c
@@ -0,0 +1,111 @@
1#include "sway/input/seat.h"
2#include "sway/input/keyboard.h"
3#include "sway/input/input-manager.h"
4#include "log.h"
5
6static void handle_keyboard_key(struct wl_listener *listener, void *data) {
7 struct sway_keyboard *keyboard =
8 wl_container_of(listener, keyboard, keyboard_key);
9 struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
10 struct wlr_input_device *wlr_device =
11 keyboard->seat_device->input_device->wlr_device;
12 struct wlr_event_keyboard_key *event = data;
13 wlr_seat_set_keyboard(wlr_seat, wlr_device);
14 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
15 event->keycode, event->state);
16}
17
18static void handle_keyboard_modifiers(struct wl_listener *listener,
19 void *data) {
20 struct sway_keyboard *keyboard =
21 wl_container_of(listener, keyboard, keyboard_modifiers);
22 struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
23 struct wlr_input_device *wlr_device =
24 keyboard->seat_device->input_device->wlr_device;
25 wlr_seat_set_keyboard(wlr_seat, wlr_device);
26 wlr_seat_keyboard_notify_modifiers(wlr_seat);
27}
28
29struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
30 struct sway_seat_device *device) {
31 struct sway_keyboard *keyboard =
32 calloc(1, sizeof(struct sway_keyboard));
33 if (!sway_assert(keyboard, "could not allocate sway keyboard")) {
34 return NULL;
35 }
36
37 keyboard->seat_device = device;
38 device->keyboard = keyboard;
39
40 wl_list_init(&keyboard->keyboard_key.link);
41 wl_list_init(&keyboard->keyboard_modifiers.link);
42
43 return keyboard;
44}
45
46void sway_keyboard_configure(struct sway_keyboard *keyboard) {
47 struct xkb_rule_names rules;
48 memset(&rules, 0, sizeof(rules));
49 struct input_config *input_config =
50 keyboard->seat_device->input_device->config;
51 struct wlr_input_device *wlr_device =
52 keyboard->seat_device->input_device->wlr_device;
53
54 if (input_config && input_config->xkb_layout) {
55 rules.layout = input_config->xkb_layout;
56 } else {
57 rules.layout = getenv("XKB_DEFAULT_LAYOUT");
58 }
59 if (input_config && input_config->xkb_model) {
60 rules.model = input_config->xkb_model;
61 } else {
62 rules.model = getenv("XKB_DEFAULT_MODEL");
63 }
64
65 if (input_config && input_config->xkb_options) {
66 rules.options = input_config->xkb_options;
67 } else {
68 rules.options = getenv("XKB_DEFAULT_OPTIONS");
69 }
70
71 if (input_config && input_config->xkb_rules) {
72 rules.rules = input_config->xkb_rules;
73 } else {
74 rules.rules = getenv("XKB_DEFAULT_RULES");
75 }
76
77 if (input_config && input_config->xkb_variant) {
78 rules.variant = input_config->xkb_variant;
79 } else {
80 rules.variant = getenv("XKB_DEFAULT_VARIANT");
81 }
82
83 struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
84 if (!sway_assert(context, "cannot create XKB context")) {
85 return;
86 }
87
88 xkb_keymap_unref(keyboard->keymap);
89 keyboard->keymap =
90 xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
91 wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap);
92 wlr_keyboard_set_repeat_info(wlr_device->keyboard, 25, 600);
93 xkb_context_unref(context);
94
95 wl_list_remove(&keyboard->keyboard_key.link);
96 wl_signal_add(&wlr_device->keyboard->events.key, &keyboard->keyboard_key);
97 keyboard->keyboard_key.notify = handle_keyboard_key;
98
99 wl_list_remove(&keyboard->keyboard_modifiers.link);
100 wl_signal_add( &wlr_device->keyboard->events.modifiers,
101 &keyboard->keyboard_modifiers);
102 keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
103}
104
105void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
106 xkb_keymap_unref(keyboard->keymap);
107 wl_list_remove(&keyboard->keyboard_key.link);
108 wl_list_remove(&keyboard->keyboard_modifiers.link);
109 wl_list_remove(&keyboard->link);
110 free(keyboard);
111}
diff --git a/sway/input/seat.c b/sway/input/seat.c
new file mode 100644
index 00000000..1b25419b
--- /dev/null
+++ b/sway/input/seat.c
@@ -0,0 +1,242 @@
1#define _XOPEN_SOURCE 700
2#include <wlr/types/wlr_cursor.h>
3#include <wlr/types/wlr_xcursor_manager.h>
4#include "sway/input/seat.h"
5#include "sway/input/cursor.h"
6#include "sway/input/input-manager.h"
7#include "sway/input/keyboard.h"
8#include "sway/output.h"
9#include "sway/view.h"
10#include "log.h"
11
12static void seat_device_destroy(struct sway_seat_device *seat_device) {
13 if (!seat_device) {
14 return;
15 }
16
17 sway_keyboard_destroy(seat_device->keyboard);
18 wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor,
19 seat_device->input_device->wlr_device);
20 wl_list_remove(&seat_device->link);
21 free(seat_device);
22}
23
24struct sway_seat *sway_seat_create(struct sway_input_manager *input,
25 const char *seat_name) {
26 struct sway_seat *seat = calloc(1, sizeof(struct sway_seat));
27 if (!seat) {
28 return NULL;
29 }
30
31 seat->wlr_seat = wlr_seat_create(input->server->wl_display, seat_name);
32 if (!sway_assert(seat->wlr_seat, "could not allocate seat")) {
33 return NULL;
34 }
35
36 seat->cursor = sway_cursor_create(seat);
37 if (!seat->cursor) {
38 wlr_seat_destroy(seat->wlr_seat);
39 free(seat);
40 return NULL;
41 }
42
43 seat->input = input;
44 wl_list_init(&seat->devices);
45
46 wlr_seat_set_capabilities(seat->wlr_seat,
47 WL_SEAT_CAPABILITY_KEYBOARD |
48 WL_SEAT_CAPABILITY_POINTER |
49 WL_SEAT_CAPABILITY_TOUCH);
50
51 sway_seat_configure_xcursor(seat);
52
53 wl_list_insert(&input->seats, &seat->link);
54
55 return seat;
56}
57
58static void seat_configure_pointer(struct sway_seat *seat,
59 struct sway_seat_device *sway_device) {
60 // TODO pointer configuration
61 wlr_cursor_attach_input_device(seat->cursor->cursor,
62 sway_device->input_device->wlr_device);
63}
64
65static void seat_configure_keyboard(struct sway_seat *seat,
66 struct sway_seat_device *seat_device) {
67 if (!seat_device->keyboard) {
68 sway_keyboard_create(seat, seat_device);
69 }
70 sway_keyboard_configure(seat_device->keyboard);
71}
72
73static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat,
74 struct sway_input_device *input_device) {
75 struct sway_seat_device *seat_device = NULL;
76 wl_list_for_each(seat_device, &seat->devices, link) {
77 if (seat_device->input_device == input_device) {
78 return seat_device;
79 }
80 }
81
82 return NULL;
83}
84
85void sway_seat_configure_device(struct sway_seat *seat,
86 struct sway_input_device *input_device) {
87 struct sway_seat_device *seat_device =
88 sway_seat_get_device(seat, input_device);
89 if (!seat_device) {
90 return;
91 }
92
93 if (seat->config) {
94 seat_device->attachment_config =
95 seat_config_get_attachment(seat->config, input_device->identifier);
96 }
97
98 switch (input_device->wlr_device->type) {
99 case WLR_INPUT_DEVICE_POINTER:
100 seat_configure_pointer(seat, seat_device);
101 break;
102 case WLR_INPUT_DEVICE_KEYBOARD:
103 seat_configure_keyboard(seat, seat_device);
104 wlr_seat_set_keyboard(seat->wlr_seat,
105 seat_device->input_device->wlr_device);
106 break;
107 case WLR_INPUT_DEVICE_TOUCH:
108 case WLR_INPUT_DEVICE_TABLET_PAD:
109 case WLR_INPUT_DEVICE_TABLET_TOOL:
110 sway_log(L_DEBUG, "TODO: configure other devices");
111 break;
112 }
113}
114
115void sway_seat_add_device(struct sway_seat *seat,
116 struct sway_input_device *input_device) {
117 if (sway_seat_get_device(seat, input_device)) {
118 return;
119 }
120
121 struct sway_seat_device *seat_device =
122 calloc(1, sizeof(struct sway_seat_device));
123 if (!seat_device) {
124 sway_log(L_DEBUG, "could not allocate seat device");
125 return;
126 }
127
128 seat_device->sway_seat = seat;
129 seat_device->input_device = input_device;
130 wl_list_insert(&seat->devices, &seat_device->link);
131
132 sway_seat_configure_device(seat, input_device);
133}
134
135void sway_seat_remove_device(struct sway_seat *seat,
136 struct sway_input_device *input_device) {
137 sway_log(L_DEBUG, "input remove: %s", input_device->identifier);
138 struct sway_seat_device *seat_device =
139 sway_seat_get_device(seat, input_device);
140
141 if (!seat_device) {
142 return;
143 }
144
145 seat_device_destroy(seat_device);
146}
147
148void sway_seat_configure_xcursor(struct sway_seat *seat) {
149 // TODO configure theme and size
150 const char *cursor_theme = "default";
151
152 if (!seat->cursor->xcursor_manager) {
153 seat->cursor->xcursor_manager =
154 wlr_xcursor_manager_create("default", 24);
155 if (sway_assert(seat->cursor->xcursor_manager,
156 "Cannot create XCursor manager for theme %s",
157 cursor_theme)) {
158 return;
159 }
160 }
161
162 for (int i = 0; i < root_container.children->length; ++i) {
163 swayc_t *output_container = root_container.children->items[i];
164 struct wlr_output *output =
165 output_container->sway_output->wlr_output;
166 bool result =
167 wlr_xcursor_manager_load(seat->cursor->xcursor_manager,
168 output->scale);
169
170 sway_assert(!result,
171 "Cannot load xcursor theme for output '%s' with scale %d",
172 output->name, output->scale);
173 }
174
175 wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager,
176 "left_ptr", seat->cursor->cursor);
177 wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x,
178 seat->cursor->cursor->y);
179}
180
181static void handle_focus_destroy(struct wl_listener *listener, void *data) {
182 struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy);
183 //swayc_t *container = data;
184
185 // TODO set new focus based on the state of the tree
186 sway_seat_set_focus(seat, NULL);
187}
188
189void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
190 swayc_t *last_focus = seat->focus;
191
192 if (last_focus == container) {
193 return;
194 }
195
196 if (last_focus) {
197 wl_list_remove(&seat->focus_destroy.link);
198 }
199
200 if (container) {
201 struct sway_view *view = container->sway_view;
202 view->iface.set_activated(view, true);
203 wl_signal_add(&container->events.destroy, &seat->focus_destroy);
204 seat->focus_destroy.notify = handle_focus_destroy;
205 wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface);
206 }
207
208 seat->focus = container;
209
210 if (last_focus &&
211 !sway_input_manager_has_focus(seat->input, last_focus)) {
212 struct sway_view *view = last_focus->sway_view;
213 view->iface.set_activated(view, false);
214
215 }
216}
217
218void sway_seat_set_config(struct sway_seat *seat,
219 struct seat_config *seat_config) {
220 // clear configs
221 seat->config = NULL;
222
223 struct sway_seat_device *seat_device = NULL;
224 wl_list_for_each(seat_device, &seat->devices, link) {
225 seat_device->attachment_config = NULL;
226 }
227
228 if (!seat_config) {
229 return;
230 }
231
232 // add configs
233 seat->config = seat_config;
234
235 wl_list_for_each(seat_device, &seat->devices, link) {
236 seat_device->attachment_config =
237 seat_config_get_attachment(seat_config,
238 seat_device->input_device->identifier);
239 sway_seat_configure_device(seat, seat_device->input_device);
240 }
241
242}
diff --git a/sway/main.c b/sway/main.c
index 8952f997..bd69395a 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -158,6 +158,7 @@ static void log_distro() {
158} 158}
159 159
160static void log_kernel() { 160static void log_kernel() {
161 return;
161 FILE *f = popen("uname -a", "r"); 162 FILE *f = popen("uname -a", "r");
162 if (!f) { 163 if (!f) {
163 sway_log(L_INFO, "Unable to determine kernel version"); 164 sway_log(L_INFO, "Unable to determine kernel version");
@@ -381,11 +382,12 @@ int main(int argc, char **argv) {
381 382
382 sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n"); 383 sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n");
383 384
385 init_layout();
386
384 if (!server_init(&server)) { 387 if (!server_init(&server)) {
385 return 1; 388 return 1;
386 } 389 }
387 390
388 init_layout();
389 ipc_init(&server); 391 ipc_init(&server);
390 log_env(); 392 log_env();
391 393
diff --git a/sway/meson.build b/sway/meson.build
index e16691a8..c1f75b13 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -2,10 +2,33 @@ sway_sources = files(
2 'main.c', 2 'main.c',
3 'server.c', 3 'server.c',
4 'commands.c', 4 'commands.c',
5 'input/input-manager.c',
6 'input/seat.c',
7 'input/cursor.c',
8 'input/keyboard.c',
5 'commands/exit.c', 9 'commands/exit.c',
6 'commands/exec.c', 10 'commands/exec.c',
7 'commands/exec_always.c', 11 'commands/exec_always.c',
8 'commands/include.c', 12 'commands/include.c',
13 'commands/input.c',
14 'commands/seat.c',
15 'commands/seat/attach.c',
16 'commands/input/accel_profile.c',
17 'commands/input/click_method.c',
18 'commands/input/drag_lock.c',
19 'commands/input/dwt.c',
20 'commands/input/events.c',
21 'commands/input/left_handed.c',
22 'commands/input/middle_emulation.c',
23 'commands/input/natural_scroll.c',
24 'commands/input/pointer_accel.c',
25 'commands/input/scroll_method.c',
26 'commands/input/tap.c',
27 'commands/input/xkb_layout.c',
28 'commands/input/xkb_model.c',
29 'commands/input/xkb_options.c',
30 'commands/input/xkb_rules.c',
31 'commands/input/xkb_variant.c',
9 'commands/output.c', 32 'commands/output.c',
10 'config.c', 33 'config.c',
11 'config/output.c', 34 'config/output.c',
@@ -28,6 +51,8 @@ sway_deps = [
28 wlroots, 51 wlroots,
29 libcap, 52 libcap,
30 math, 53 math,
54 libinput,
55 xkbcommon,
31] 56]
32 57
33executable( 58executable(
diff --git a/sway/server.c b/sway/server.c
index 024d8429..32c8f03c 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -11,6 +11,7 @@
11// TODO WLR: make Xwayland optional 11// TODO WLR: make Xwayland optional
12#include <wlr/xwayland.h> 12#include <wlr/xwayland.h>
13#include "sway/server.h" 13#include "sway/server.h"
14#include "sway/input/input-manager.h"
14#include "log.h" 15#include "log.h"
15 16
16bool server_init(struct sway_server *server) { 17bool server_init(struct sway_server *server) {
@@ -58,6 +59,9 @@ bool server_init(struct sway_server *server) {
58 wlr_backend_destroy(server->backend); 59 wlr_backend_destroy(server->backend);
59 return false; 60 return false;
60 } 61 }
62
63 input_manager = sway_input_manager_create(server);
64
61 return true; 65 return true;
62} 66}
63 67
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 5df10bcb..6f2a3abf 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -4,6 +4,7 @@
4#include <string.h> 4#include <string.h>
5#include <strings.h> 5#include <strings.h>
6#include <wlr/types/wlr_output_layout.h> 6#include <wlr/types/wlr_output_layout.h>
7#include <wlr/types/wlr_wl_shell.h>
7#include "sway/config.h" 8#include "sway/config.h"
8#include "sway/container.h" 9#include "sway/container.h"
9#include "sway/layout.h" 10#include "sway/layout.h"
@@ -42,6 +43,9 @@ static swayc_t *new_swayc(enum swayc_types type) {
42 if (type != C_VIEW) { 43 if (type != C_VIEW) {
43 c->children = create_list(); 44 c->children = create_list();
44 } 45 }
46
47 wl_signal_init(&c->events.destroy);
48
45 return c; 49 return c;
46} 50}
47 51
@@ -140,6 +144,9 @@ static void free_swayc(swayc_t *cont) {
140 if (!sway_assert(cont, "free_swayc passed NULL")) { 144 if (!sway_assert(cont, "free_swayc passed NULL")) {
141 return; 145 return;
142 } 146 }
147
148 wl_signal_emit(&cont->events.destroy, cont);
149
143 if (cont->children) { 150 if (cont->children) {
144 // remove children until there are no more, free_swayc calls 151 // remove children until there are no more, free_swayc calls
145 // remove_child, which removes child from this container 152 // remove_child, which removes child from this container
@@ -218,3 +225,63 @@ swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
218 } while (container && container->type != type); 225 } while (container && container->type != type);
219 return container; 226 return container;
220} 227}
228
229swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
230 struct wlr_surface **surface, double *sx, double *sy) {
231 list_t *queue = create_list();
232 list_add(queue, parent);
233
234 swayc_t *swayc = NULL;
235 while (queue->length) {
236 swayc = queue->items[0];
237 list_del(queue, 0);
238 if (swayc->type == C_VIEW) {
239 struct sway_view *sview = swayc->sway_view;
240 swayc_t *soutput = swayc_parent_by_type(swayc, C_OUTPUT);
241 struct wlr_box *output_box =
242 wlr_output_layout_get_box(
243 root_container.sway_root->output_layout,
244 soutput->sway_output->wlr_output);
245 double ox = lx - output_box->x;
246 double oy = ly - output_box->y;
247 double view_sx = ox - swayc->x;
248 double view_sy = oy - swayc->y;
249 int width = swayc->sway_view->surface->current->width;
250 int height = swayc->sway_view->surface->current->height;
251
252 // TODO popups and subsurfaces
253 switch (sview->type) {
254 case SWAY_WL_SHELL_VIEW:
255 break;
256 case SWAY_XDG_SHELL_V6_VIEW:
257 // the top left corner of the sway container is the
258 // coordinate of the top left corner of the window geometry
259 view_sx += sview->wlr_xdg_surface_v6->geometry->x;
260 view_sy += sview->wlr_xdg_surface_v6->geometry->y;
261 break;
262 case SWAY_XWAYLAND_VIEW:
263 break;
264 default:
265 break;
266 }
267
268 if (view_sx > 0 && view_sx < width &&
269 view_sy > 0 && view_sy < height &&
270 pixman_region32_contains_point(
271 &sview->surface->current->input,
272 view_sx, view_sy, NULL)) {
273 *sx = view_sx;
274 *sy = view_sy;
275 *surface = swayc->sway_view->surface;
276 list_free(queue);
277 return swayc;
278 }
279 } else {
280 list_cat(queue, swayc->children);
281 }
282 }
283
284 list_free(queue);
285
286 return NULL;
287}