aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2017-12-20 11:56:39 -0500
committerLibravatar GitHub <noreply@github.com>2017-12-20 11:56:39 -0500
commit373def44468e0c919031a6ffe3049f91680e05ca (patch)
treee40dfdcc9292a71fcc2160bc5d643a66996664dc
parentMerge pull request #1527 from martinetd/mesondep (diff)
parentcleanup (diff)
downloadsway-373def44468e0c919031a6ffe3049f91680e05ca.tar.gz
sway-373def44468e0c919031a6ffe3049f91680e05ca.tar.zst
sway-373def44468e0c919031a6ffe3049f91680e05ca.zip
Merge pull request #1505 from acrisci/feature/input
input management and seat
-rw-r--r--include/sway/commands.h13
-rw-r--r--include/sway/config.h36
-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.h22
-rw-r--r--include/sway/input/seat.h47
-rw-r--r--include/sway/ipc-json.h2
-rw-r--r--include/sway/server.h2
-rw-r--r--meson.build1
-rw-r--r--sway/commands.c105
-rw-r--r--sway/commands/input.c65
-rw-r--r--sway/commands/input/accel_profile.c30
-rw-r--r--sway/commands/input/click_method.c35
-rw-r--r--sway/commands/input/drag_lock.c30
-rw-r--r--sway/commands/input/dwt.c29
-rw-r--r--sway/commands/input/events.c36
-rw-r--r--sway/commands/input/left_handed.c30
-rw-r--r--sway/commands/input/middle_emulation.c31
-rw-r--r--sway/commands/input/natural_scroll.c30
-rw-r--r--sway/commands/input/pointer_accel.c28
-rw-r--r--sway/commands/input/scroll_method.c34
-rw-r--r--sway/commands/input/tap.c33
-rw-r--r--sway/commands/input/xkb_layout.c25
-rw-r--r--sway/commands/input/xkb_model.c25
-rw-r--r--sway/commands/input/xkb_options.c25
-rw-r--r--sway/commands/input/xkb_rules.c25
-rw-r--r--sway/commands/input/xkb_variant.c25
-rw-r--r--sway/commands/seat.c37
-rw-r--r--sway/commands/seat/attach.c26
-rw-r--r--sway/commands/seat/fallback.c29
-rw-r--r--sway/config.c54
-rw-r--r--sway/config/input.c105
-rw-r--r--sway/config/seat.c135
-rw-r--r--sway/desktop/output.c26
-rw-r--r--sway/desktop/wl_shell.c6
-rw-r--r--sway/desktop/xdg_shell_v6.c6
-rw-r--r--sway/desktop/xwayland.c5
-rw-r--r--sway/input/cursor.c181
-rw-r--r--sway/input/input-manager.c293
-rw-r--r--sway/input/input.c77
-rw-r--r--sway/input/keyboard.c123
-rw-r--r--sway/input/seat.c253
-rw-r--r--sway/ipc-json.c37
-rw-r--r--sway/ipc-server.c14
-rw-r--r--sway/main.c4
-rw-r--r--sway/meson.build28
-rw-r--r--sway/server.c4
-rw-r--r--sway/sway-input.5.txt54
-rw-r--r--sway/sway.1.txt23
-rw-r--r--sway/sway.5.txt7
-rw-r--r--sway/tree/container.c67
-rw-r--r--swaymsg/main.c78
53 files changed, 2324 insertions, 199 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index b1f0423d..4ee7af2a 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,
@@ -107,6 +110,7 @@ sway_cmd cmd_gaps;
107sway_cmd cmd_hide_edge_borders; 110sway_cmd cmd_hide_edge_borders;
108sway_cmd cmd_include; 111sway_cmd cmd_include;
109sway_cmd cmd_input; 112sway_cmd cmd_input;
113sway_cmd cmd_seat;
110sway_cmd cmd_ipc; 114sway_cmd cmd_ipc;
111sway_cmd cmd_kill; 115sway_cmd cmd_kill;
112sway_cmd cmd_layout; 116sway_cmd cmd_layout;
@@ -176,6 +180,7 @@ sway_cmd bar_colors_cmd_statusline;
176sway_cmd bar_colors_cmd_focused_statusline; 180sway_cmd bar_colors_cmd_focused_statusline;
177sway_cmd bar_colors_cmd_urgent_workspace; 181sway_cmd bar_colors_cmd_urgent_workspace;
178 182
183sway_cmd input_cmd_seat;
179sway_cmd input_cmd_accel_profile; 184sway_cmd input_cmd_accel_profile;
180sway_cmd input_cmd_click_method; 185sway_cmd input_cmd_click_method;
181sway_cmd input_cmd_drag_lock; 186sway_cmd input_cmd_drag_lock;
@@ -187,6 +192,14 @@ sway_cmd input_cmd_natural_scroll;
187sway_cmd input_cmd_pointer_accel; 192sway_cmd input_cmd_pointer_accel;
188sway_cmd input_cmd_scroll_method; 193sway_cmd input_cmd_scroll_method;
189sway_cmd input_cmd_tap; 194sway_cmd input_cmd_tap;
195sway_cmd input_cmd_xkb_layout;
196sway_cmd input_cmd_xkb_model;
197sway_cmd input_cmd_xkb_options;
198sway_cmd input_cmd_xkb_rules;
199sway_cmd input_cmd_xkb_variant;
200
201sway_cmd seat_cmd_fallback;
202sway_cmd seat_cmd_attach;
190 203
191sway_cmd cmd_ipc_cmd; 204sway_cmd cmd_ipc_cmd;
192sway_cmd cmd_ipc_events; 205sway_cmd cmd_ipc_events;
diff --git a/include/sway/config.h b/include/sway/config.h
index afff2738..83ded720 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -67,11 +67,34 @@ 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 int fallback; // -1 means not set
94 list_t *attachments; // list of seat_attachment configs
95};
96
97/**
75 * Size and position configuration for a particular output. 98 * Size and position configuration for a particular output.
76 * 99 *
77 * This is set via the `output` command. 100 * This is set via the `output` command.
@@ -262,6 +285,7 @@ struct sway_config {
262 list_t *pid_workspaces; 285 list_t *pid_workspaces;
263 list_t *output_configs; 286 list_t *output_configs;
264 list_t *input_configs; 287 list_t *input_configs;
288 list_t *seat_configs;
265 list_t *criteria; 289 list_t *criteria;
266 list_t *no_focus; 290 list_t *no_focus;
267 list_t *active_bar_modifiers; 291 list_t *active_bar_modifiers;
@@ -358,9 +382,19 @@ char *do_var_replacement(char *str);
358struct cmd_results *check_security_config(); 382struct cmd_results *check_security_config();
359 383
360int input_identifier_cmp(const void *item, const void *data); 384int input_identifier_cmp(const void *item, const void *data);
385struct input_config *new_input_config(const char* identifier);
361void merge_input_config(struct input_config *dst, struct input_config *src); 386void 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); 387void free_input_config(struct input_config *ic);
388void apply_input_config(struct input_config *input);
389
390int seat_name_cmp(const void *item, const void *data);
391struct seat_config *new_seat_config(const char* name);
392void merge_seat_config(struct seat_config *dst, struct seat_config *src);
393void free_seat_config(struct seat_config *ic);
394struct seat_attachment_config *seat_attachment_config_new();
395struct seat_attachment_config *seat_config_get_attachment(
396 struct seat_config *seat_config, char *identifier);
397void apply_seat_config(struct seat_config *seat);
364 398
365int output_name_cmp(const void *item, const void *data); 399int output_name_cmp(const void *item, const void *data);
366struct output_config *new_output_config(); 400struct output_config *new_output_config();
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..2f70cf4b
--- /dev/null
+++ b/include/sway/input/cursor.h
@@ -0,0 +1,30 @@
1#ifndef _SWAY_INPUT_CURSOR_H
2#define _SWAY_INPUT_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..53064eed
--- /dev/null
+++ b/include/sway/input/input-manager.h
@@ -0,0 +1,49 @@
1#ifndef _SWAY_INPUT_INPUT_MANAGER_H
2#define _SWAY_INPUT_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..d9251f4c
--- /dev/null
+++ b/include/sway/input/keyboard.h
@@ -0,0 +1,22 @@
1#ifndef _SWAY_INPUT_KEYBOARD_H
2#define _SWAY_INPUT_KEYBOARD_H
3
4#include "sway/input/seat.h"
5
6struct sway_keyboard {
7 struct sway_seat_device *seat_device;
8
9 struct xkb_keymap *keymap;
10
11 struct wl_listener keyboard_key;
12 struct wl_listener keyboard_modifiers;
13};
14
15struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
16 struct sway_seat_device *device);
17
18void sway_keyboard_configure(struct sway_keyboard *keyboard);
19
20void sway_keyboard_destroy(struct sway_keyboard *keyboard);
21
22#endif
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
new file mode 100644
index 00000000..d703f94c
--- /dev/null
+++ b/include/sway/input/seat.h
@@ -0,0 +1,47 @@
1#ifndef _SWAY_INPUT_SEAT_H
2#define _SWAY_INPUT_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/ipc-json.h b/include/sway/ipc-json.h
index 9435b664..eef5a018 100644
--- a/include/sway/ipc-json.h
+++ b/include/sway/ipc-json.h
@@ -2,10 +2,12 @@
2#define _SWAY_IPC_JSON_H 2#define _SWAY_IPC_JSON_H
3#include <json-c/json.h> 3#include <json-c/json.h>
4#include "sway/container.h" 4#include "sway/container.h"
5#include "sway/input/input-manager.h"
5 6
6json_object *ipc_json_get_version(); 7json_object *ipc_json_get_version();
7 8
8json_object *ipc_json_describe_container(swayc_t *c); 9json_object *ipc_json_describe_container(swayc_t *c);
9json_object *ipc_json_describe_container_recursive(swayc_t *c); 10json_object *ipc_json_describe_container_recursive(swayc_t *c);
11json_object *ipc_json_describe_input(struct sway_input_device *device);
10 12
11#endif 13#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..34afb6a0 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 apply_input_config(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 apply_seat_config(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,51 @@ 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 { "fallback", seat_cmd_fallback },
169};
170
108static struct cmd_handler *find_handler(char *line, enum cmd_status block) { 171static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
109 struct cmd_handler d = { .command=line }; 172 struct cmd_handler d = { .command=line };
110 struct cmd_handler *res = NULL; 173 struct cmd_handler *res = NULL;
111 sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT); 174 sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT);
112 /* TODO 175
113 if (block == CMD_BLOCK_BAR) { 176 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, 177 res = bsearch(&d, input_handlers,
123 sizeof(input_handlers) / sizeof(struct cmd_handler), 178 sizeof(input_handlers) / sizeof(struct cmd_handler),
124 sizeof(struct cmd_handler), handler_compare); 179 sizeof(struct cmd_handler), handler_compare);
125 } else if (block == CMD_BLOCK_IPC) { 180 } else if (block == CMD_BLOCK_SEAT) {
126 res = bsearch(&d, ipc_handlers, 181 res = bsearch(&d, seat_handlers,
127 sizeof(ipc_handlers) / sizeof(struct cmd_handler), 182 sizeof(seat_handlers) / sizeof(struct cmd_handler),
128 sizeof(struct cmd_handler), handler_compare); 183 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 { 184 } else {
134 */
135 res = bsearch(&d, handlers, 185 res = bsearch(&d, handlers,
136 sizeof(handlers) / sizeof(struct cmd_handler), 186 sizeof(handlers) / sizeof(struct cmd_handler),
137 sizeof(struct cmd_handler), handler_compare); 187 sizeof(struct cmd_handler), handler_compare);
138 //} 188 }
189
139 return res; 190 return res;
140} 191}
141 192
@@ -239,8 +290,8 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) {
239 argv[i] = do_var_replacement(argv[i]); 290 argv[i] = do_var_replacement(argv[i]);
240 unescape_string(argv[i]); 291 unescape_string(argv[i]);
241 } 292 }
242 /* Strip quotes for first argument. 293 // Strip quotes for first argument.
243 * TODO This part needs to be handled much better */ 294 // TODO This part needs to be handled much better
244 if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { 295 if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
245 strip_quotes(argv[1]); 296 strip_quotes(argv[1]);
246 } 297 }
diff --git a/sway/commands/input.c b/sway/commands/input.c
new file mode 100644
index 00000000..ccb1d276
--- /dev/null
+++ b/sway/commands/input.c
@@ -0,0 +1,65 @@
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 ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 3))) {
20 return error;
21 }
22
23 int argc_new = argc-2;
24 char **argv_new = argv+2;
25
26 struct cmd_results *res;
27 current_input_config = new_input_config(argv[0]);
28 if (strcasecmp("accel_profile", argv[1]) == 0) {
29 res = input_cmd_accel_profile(argc_new, argv_new);
30 } else if (strcasecmp("click_method", argv[1]) == 0) {
31 res = input_cmd_click_method(argc_new, argv_new);
32 } else if (strcasecmp("drag_lock", argv[1]) == 0) {
33 res = input_cmd_drag_lock(argc_new, argv_new);
34 } else if (strcasecmp("dwt", argv[1]) == 0) {
35 res = input_cmd_dwt(argc_new, argv_new);
36 } else if (strcasecmp("events", argv[1]) == 0) {
37 res = input_cmd_events(argc_new, argv_new);
38 } else if (strcasecmp("left_handed", argv[1]) == 0) {
39 res = input_cmd_left_handed(argc_new, argv_new);
40 } else if (strcasecmp("middle_emulation", argv[1]) == 0) {
41 res = input_cmd_middle_emulation(argc_new, argv_new);
42 } else if (strcasecmp("natural_scroll", argv[1]) == 0) {
43 res = input_cmd_natural_scroll(argc_new, argv_new);
44 } else if (strcasecmp("pointer_accel", argv[1]) == 0) {
45 res = input_cmd_pointer_accel(argc_new, argv_new);
46 } else if (strcasecmp("scroll_method", argv[1]) == 0) {
47 res = input_cmd_scroll_method(argc_new, argv_new);
48 } else if (strcasecmp("tap", argv[1]) == 0) {
49 res = input_cmd_tap(argc_new, argv_new);
50 } else if (strcasecmp("xkb_layout", argv[1]) == 0) {
51 res = input_cmd_xkb_layout(argc_new, argv_new);
52 } else if (strcasecmp("xkb_model", argv[1]) == 0) {
53 res = input_cmd_xkb_model(argc_new, argv_new);
54 } else if (strcasecmp("xkb_options", argv[1]) == 0) {
55 res = input_cmd_xkb_options(argc_new, argv_new);
56 } else if (strcasecmp("xkb_rules", argv[1]) == 0) {
57 res = input_cmd_xkb_rules(argc_new, argv_new);
58 } else if (strcasecmp("xkb_variant", argv[1]) == 0) {
59 res = input_cmd_xkb_variant(argc_new, argv_new);
60 } else {
61 res = cmd_results_new(CMD_INVALID, "input <device>", "Unknown command %s", argv[1]);
62 }
63 current_input_config = NULL;
64 return res;
65}
diff --git a/sway/commands/input/accel_profile.c b/sway/commands/input/accel_profile.c
new file mode 100644
index 00000000..f72b7d48
--- /dev/null
+++ b/sway/commands/input/accel_profile.c
@@ -0,0 +1,30 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_accel_profile(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "accel_profile",
14 "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], "adaptive") == 0) {
20 new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
21 } else if (strcasecmp(argv[0], "flat") == 0) {
22 new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
23 } else {
24 return cmd_results_new(CMD_INVALID, "accel_profile",
25 "Expected 'accel_profile <adaptive|flat>'");
26 }
27
28 apply_input_config(new_config);
29 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
30}
diff --git a/sway/commands/input/click_method.c b/sway/commands/input/click_method.c
new file mode 100644
index 00000000..dcf64c1a
--- /dev/null
+++ b/sway/commands/input/click_method.c
@@ -0,0 +1,35 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4#include "sway/config.h"
5#include "sway/input/input-manager.h"
6#include "log.h"
7
8struct cmd_results *input_cmd_click_method(int argc, char **argv) {
9 sway_log(L_DEBUG, "click_method for device: %d %s",
10 current_input_config==NULL, current_input_config->identifier);
11 struct cmd_results *error = NULL;
12 if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) {
13 return error;
14 }
15 if (!current_input_config) {
16 return cmd_results_new(CMD_FAILURE, "click_method",
17 "No input device defined.");
18 }
19 struct input_config *new_config =
20 new_input_config(current_input_config->identifier);
21
22 if (strcasecmp(argv[0], "none") == 0) {
23 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
24 } else if (strcasecmp(argv[0], "button_areas") == 0) {
25 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
26 } else if (strcasecmp(argv[0], "clickfinger") == 0) {
27 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
28 } else {
29 return cmd_results_new(CMD_INVALID, "click_method",
30 "Expected 'click_method <none|button_areas|clickfinger'");
31 }
32
33 apply_input_config(new_config);
34 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
35}
diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c
new file mode 100644
index 00000000..1783978a
--- /dev/null
+++ b/sway/commands/input/drag_lock.c
@@ -0,0 +1,30 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE,
14 "drag_lock", "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->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
21 } else if (strcasecmp(argv[0], "disabled") == 0) {
22 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
23 } else {
24 return cmd_results_new(CMD_INVALID, "drag_lock",
25 "Expected 'drag_lock <enabled|disabled>'");
26 }
27
28 apply_input_config(new_config);
29 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
30}
diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c
new file mode 100644
index 00000000..8108a110
--- /dev/null
+++ b/sway/commands/input/dwt.c
@@ -0,0 +1,29 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_dwt(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "dwt", "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->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
20 } else if (strcasecmp(argv[0], "disabled") == 0) {
21 new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
22 } else {
23 return cmd_results_new(CMD_INVALID, "dwt",
24 "Expected 'dwt <enabled|disabled>'");
25 }
26
27 apply_input_config(new_config);
28 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
29}
diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c
new file mode 100644
index 00000000..8a74c11e
--- /dev/null
+++ b/sway/commands/input/events.c
@@ -0,0 +1,36 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6#include "log.h"
7
8struct cmd_results *input_cmd_events(int argc, char **argv) {
9 sway_log(L_DEBUG, "events for device: %s",
10 current_input_config->identifier);
11 struct cmd_results *error = NULL;
12 if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) {
13 return error;
14 }
15 if (!current_input_config) {
16 return cmd_results_new(CMD_FAILURE, "events",
17 "No input device defined.");
18 }
19 struct input_config *new_config =
20 new_input_config(current_input_config->identifier);
21
22 if (strcasecmp(argv[0], "enabled") == 0) {
23 new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
24 } else if (strcasecmp(argv[0], "disabled") == 0) {
25 new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
26 } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) {
27 new_config->send_events =
28 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
29 } else {
30 return cmd_results_new(CMD_INVALID, "events",
31 "Expected 'events <enabled|disabled|disabled_on_external_mouse>'");
32 }
33
34 apply_input_config(new_config);
35 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
36}
diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c
new file mode 100644
index 00000000..35740df3
--- /dev/null
+++ b/sway/commands/input/left_handed.c
@@ -0,0 +1,30 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "left_handed",
14 "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->left_handed = 1;
21 } else if (strcasecmp(argv[0], "disabled") == 0) {
22 new_config->left_handed = 0;
23 } else {
24 return cmd_results_new(CMD_INVALID, "left_handed",
25 "Expected 'left_handed <enabled|disabled>'");
26 }
27
28 apply_input_config(new_config);
29 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
30}
diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c
new file mode 100644
index 00000000..7bc08ae6
--- /dev/null
+++ b/sway/commands/input/middle_emulation.c
@@ -0,0 +1,31 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "middle_emulation",
14 "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->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
21 } else if (strcasecmp(argv[0], "disabled") == 0) {
22 new_config->middle_emulation =
23 LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
24 } else {
25 return cmd_results_new(CMD_INVALID, "middle_emulation",
26 "Expected 'middle_emulation <enabled|disabled>'");
27 }
28
29 apply_input_config(new_config);
30 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
31}
diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c
new file mode 100644
index 00000000..a7dcdc2c
--- /dev/null
+++ b/sway/commands/input/natural_scroll.c
@@ -0,0 +1,30 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "natural_scoll",
14 "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->natural_scroll = 1;
21 } else if (strcasecmp(argv[0], "disabled") == 0) {
22 new_config->natural_scroll = 0;
23 } else {
24 return cmd_results_new(CMD_INVALID, "natural_scroll",
25 "Expected 'natural_scroll <enabled|disabled>'");
26 }
27
28 apply_input_config(new_config);
29 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
30}
diff --git a/sway/commands/input/pointer_accel.c b/sway/commands/input/pointer_accel.c
new file mode 100644
index 00000000..d2261a63
--- /dev/null
+++ b/sway/commands/input/pointer_accel.c
@@ -0,0 +1,28 @@
1#include <stdlib.h>
2#include <string.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE,
14 "pointer_accel", "No input device defined.");
15 }
16 struct input_config *new_config =
17 new_input_config(current_input_config->identifier);
18
19 float pointer_accel = atof(argv[0]);
20 if (pointer_accel < -1 || pointer_accel > 1) {
21 return cmd_results_new(CMD_INVALID, "pointer_accel",
22 "Input out of range [-1, 1]");
23 }
24 new_config->pointer_accel = pointer_accel;
25
26 apply_input_config(new_config);
27 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
28}
diff --git a/sway/commands/input/scroll_method.c b/sway/commands/input/scroll_method.c
new file mode 100644
index 00000000..035262cf
--- /dev/null
+++ b/sway/commands/input/scroll_method.c
@@ -0,0 +1,34 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_scroll_method(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "scroll_method",
14 "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], "none") == 0) {
20 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
21 } else if (strcasecmp(argv[0], "two_finger") == 0) {
22 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
23 } else if (strcasecmp(argv[0], "edge") == 0) {
24 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
25 } else if (strcasecmp(argv[0], "on_button_down") == 0) {
26 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
27 } else {
28 return cmd_results_new(CMD_INVALID, "scroll_method",
29 "Expected 'scroll_method <none|two_finger|edge|on_button_down>'");
30 }
31
32 apply_input_config(new_config);
33 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
34}
diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c
new file mode 100644
index 00000000..8547c0cd
--- /dev/null
+++ b/sway/commands/input/tap.c
@@ -0,0 +1,33 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6#include "log.h"
7
8struct cmd_results *input_cmd_tap(int argc, char **argv) {
9 sway_log(L_DEBUG, "tap for device: %s", current_input_config->identifier);
10 struct cmd_results *error = NULL;
11 if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) {
12 return error;
13 }
14 if (!current_input_config) {
15 return cmd_results_new(CMD_FAILURE, "tap", "No input device defined.");
16 }
17 struct input_config *new_config =
18 new_input_config(current_input_config->identifier);
19
20 if (strcasecmp(argv[0], "enabled") == 0) {
21 new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED;
22 } else if (strcasecmp(argv[0], "disabled") == 0) {
23 new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
24 } else {
25 return cmd_results_new(CMD_INVALID, "tap",
26 "Expected 'tap <enabled|disabled>'");
27 }
28
29 sway_log(L_DEBUG, "apply-tap for device: %s",
30 current_input_config->identifier);
31 apply_input_config(new_config);
32 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
33}
diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c
new file mode 100644
index 00000000..a25d3850
--- /dev/null
+++ b/sway/commands/input/xkb_layout.c
@@ -0,0 +1,25 @@
1#define _XOPEN_SOURCE 700
2#include "sway/config.h"
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) {
8 sway_log(L_DEBUG, "xkb layout for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_layout", EXPECTED_EQUAL_TO, 1))) {
11 return error;
12 }
13 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_layout", "No input device defined.");
15 }
16 struct input_config *new_config =
17 new_input_config(current_input_config->identifier);
18
19 new_config->xkb_layout = strdup(argv[0]);
20
21 sway_log(L_DEBUG, "apply-xkb_layout for device: %s layout: %s",
22 current_input_config->identifier, new_config->xkb_layout);
23 apply_input_config(new_config);
24 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
25}
diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c
new file mode 100644
index 00000000..9729e869
--- /dev/null
+++ b/sway/commands/input/xkb_model.c
@@ -0,0 +1,25 @@
1#define _XOPEN_SOURCE 700
2#include "sway/config.h"
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *input_cmd_xkb_model(int argc, char **argv) {
8 sway_log(L_DEBUG, "xkb model for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_model", EXPECTED_EQUAL_TO, 1))) {
11 return error;
12 }
13 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_model", "No input device defined.");
15 }
16 struct input_config *new_config =
17 new_input_config(current_input_config->identifier);
18
19 new_config->xkb_model = strdup(argv[0]);
20
21 sway_log(L_DEBUG, "apply-xkb_model for device: %s model: %s",
22 current_input_config->identifier, new_config->xkb_model);
23 apply_input_config(new_config);
24 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
25}
diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c
new file mode 100644
index 00000000..504849cc
--- /dev/null
+++ b/sway/commands/input/xkb_options.c
@@ -0,0 +1,25 @@
1#define _XOPEN_SOURCE 700
2#include "sway/config.h"
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *input_cmd_xkb_options(int argc, char **argv) {
8 sway_log(L_DEBUG, "xkb options for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_options", EXPECTED_EQUAL_TO, 1))) {
11 return error;
12 }
13 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_options", "No input device defined.");
15 }
16 struct input_config *new_config =
17 new_input_config(current_input_config->identifier);
18
19 new_config->xkb_options = strdup(argv[0]);
20
21 sway_log(L_DEBUG, "apply-xkb_options for device: %s options: %s",
22 current_input_config->identifier, new_config->xkb_options);
23 apply_input_config(new_config);
24 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
25}
diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c
new file mode 100644
index 00000000..db7d8abe
--- /dev/null
+++ b/sway/commands/input/xkb_rules.c
@@ -0,0 +1,25 @@
1#define _XOPEN_SOURCE 700
2#include "sway/config.h"
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) {
8 sway_log(L_DEBUG, "xkb rules for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_rules", EXPECTED_EQUAL_TO, 1))) {
11 return error;
12 }
13 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_rules", "No input device defined.");
15 }
16 struct input_config *new_config =
17 new_input_config(current_input_config->identifier);
18
19 new_config->xkb_rules = strdup(argv[0]);
20
21 sway_log(L_DEBUG, "apply-xkb_rules for device: %s rules: %s",
22 current_input_config->identifier, new_config->xkb_rules);
23 apply_input_config(new_config);
24 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
25}
diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c
new file mode 100644
index 00000000..855e6abc
--- /dev/null
+++ b/sway/commands/input/xkb_variant.c
@@ -0,0 +1,25 @@
1#define _XOPEN_SOURCE 700
2#include "sway/config.h"
3#include "sway/commands.h"
4#include "sway/input/input-manager.h"
5#include "log.h"
6
7struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) {
8 sway_log(L_DEBUG, "xkb variant for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_variant", EXPECTED_EQUAL_TO, 1))) {
11 return error;
12 }
13 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_variant", "No input device defined.");
15 }
16 struct input_config *new_config =
17 new_input_config(current_input_config->identifier);
18
19 new_config->xkb_variant = strdup(argv[0]);
20
21 sway_log(L_DEBUG, "apply-xkb_variant for device: %s variant: %s",
22 current_input_config->identifier, new_config->xkb_variant);
23 apply_input_config(new_config);
24 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
25}
diff --git a/sway/commands/seat.c b/sway/commands/seat.c
new file mode 100644
index 00000000..155bc510
--- /dev/null
+++ b/sway/commands/seat.c
@@ -0,0 +1,37 @@
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 ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 3))) {
20 return error;
21 }
22
23 int argc_new = argc-2;
24 char **argv_new = argv+2;
25
26 struct cmd_results *res;
27 current_seat_config = new_seat_config(argv[0]);
28 if (strcasecmp("attach", argv[1]) == 0) {
29 res = seat_cmd_attach(argc_new, argv_new);
30 } else if (strcasecmp("fallback", argv[1]) == 0) {
31 res = seat_cmd_fallback(argc_new, argv_new);
32 } else {
33 res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]);
34 }
35 current_seat_config = NULL;
36 return res;
37}
diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c
new file mode 100644
index 00000000..80ec63ce
--- /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 apply_seat_config(new_config);
25 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
26}
diff --git a/sway/commands/seat/fallback.c b/sway/commands/seat/fallback.c
new file mode 100644
index 00000000..7c129aae
--- /dev/null
+++ b/sway/commands/seat/fallback.c
@@ -0,0 +1,29 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *seat_cmd_fallback(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "fallback", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 if (!current_seat_config) {
13 return cmd_results_new(CMD_FAILURE, "fallback", "No seat defined");
14 }
15 struct seat_config *new_config =
16 new_seat_config(current_seat_config->name);
17
18 if (strcasecmp(argv[0], "true") == 0) {
19 new_config->fallback = 1;
20 } else if (strcasecmp(argv[0], "false") == 0) {
21 new_config->fallback = 0;
22 } else {
23 return cmd_results_new(CMD_INVALID, "fallback",
24 "Expected 'fallback <true|false>'");
25 }
26
27 apply_seat_config(new_config);
28 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
29}
diff --git a/sway/config.c b/sway/config.c
index 61131845..b591ae9e 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -12,7 +12,6 @@
12#include <signal.h> 12#include <signal.h>
13#include <libinput.h> 13#include <libinput.h>
14#include <limits.h> 14#include <limits.h>
15#include <float.h>
16#include <dirent.h> 15#include <dirent.h>
17#include <strings.h> 16#include <strings.h>
18#ifdef __linux__ 17#ifdef __linux__
@@ -21,6 +20,7 @@
21#include <dev/evdev/input-event-codes.h> 20#include <dev/evdev/input-event-codes.h>
22#endif 21#endif
23#include <wlr/types/wlr_output.h> 22#include <wlr/types/wlr_output.h>
23#include "sway/input/input-manager.h"
24#include "sway/commands.h" 24#include "sway/commands.h"
25#include "sway/config.h" 25#include "sway/config.h"
26#include "sway/layout.h" 26#include "sway/layout.h"
@@ -44,11 +44,13 @@ static void config_defaults(struct sway_config *config) {
44 if (!(config->criteria = create_list())) goto cleanup; 44 if (!(config->criteria = create_list())) goto cleanup;
45 if (!(config->no_focus = create_list())) goto cleanup; 45 if (!(config->no_focus = create_list())) goto cleanup;
46 if (!(config->input_configs = create_list())) goto cleanup; 46 if (!(config->input_configs = create_list())) goto cleanup;
47 if (!(config->seat_configs = create_list())) goto cleanup;
47 if (!(config->output_configs = create_list())) goto cleanup; 48 if (!(config->output_configs = create_list())) goto cleanup;
48 49
49 if (!(config->cmd_queue = create_list())) goto cleanup; 50 if (!(config->cmd_queue = create_list())) goto cleanup;
50 51
51 if (!(config->current_mode = malloc(sizeof(struct sway_mode)))) goto cleanup; 52 if (!(config->current_mode = malloc(sizeof(struct sway_mode))))
53 goto cleanup;
52 if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; 54 if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup;
53 strcpy(config->current_mode->name, "default"); 55 strcpy(config->current_mode->name, "default");
54 if (!(config->current_mode->bindings = create_list())) goto cleanup; 56 if (!(config->current_mode->bindings = create_list())) goto cleanup;
@@ -256,8 +258,9 @@ bool load_main_config(const char *file, bool is_active) {
256 bool success = true; 258 bool success = true;
257 DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); 259 DIR *dir = opendir(SYSCONFDIR "/sway/security.d");
258 if (!dir) { 260 if (!dir) {
259 sway_log(L_ERROR, "%s does not exist, sway will have no security configuration" 261 sway_log(L_ERROR,
260 " and will probably be broken", SYSCONFDIR "/sway/security.d"); 262 "%s does not exist, sway will have no security configuration"
263 " and will probably be broken", SYSCONFDIR "/sway/security.d");
261 } else { 264 } else {
262 list_t *secconfigs = create_list(); 265 list_t *secconfigs = create_list();
263 char *base = SYSCONFDIR "/sway/security.d/"; 266 char *base = SYSCONFDIR "/sway/security.d/";
@@ -281,8 +284,12 @@ bool load_main_config(const char *file, bool is_active) {
281 list_qsort(secconfigs, qstrcmp); 284 list_qsort(secconfigs, qstrcmp);
282 for (int i = 0; i < secconfigs->length; ++i) { 285 for (int i = 0; i < secconfigs->length; ++i) {
283 char *_path = secconfigs->items[i]; 286 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)) { 287 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); 288 (((s.st_mode & 0777) != 0644) &&
289 (s.st_mode & 0777) != 0444)) {
290 sway_log(L_ERROR,
291 "Refusing to load %s - it must be owned by root "
292 "and mode 644 or 444", _path);
286 success = false; 293 success = false;
287 } else { 294 } else {
288 success = success && load_config(_path, config); 295 success = success && load_config(_path, config);
@@ -311,7 +318,8 @@ bool load_main_config(const char *file, bool is_active) {
311 return success; 318 return success;
312} 319}
313 320
314static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { 321static bool load_include_config(const char *path, const char *parent_dir,
322 struct sway_config *config) {
315 // save parent config 323 // save parent config
316 const char *parent_config = config->current_config; 324 const char *parent_config = config->current_config;
317 325
@@ -321,7 +329,8 @@ static bool load_include_config(const char *path, const char *parent_dir, struct
321 len = len + strlen(parent_dir) + 2; 329 len = len + strlen(parent_dir) + 2;
322 full_path = malloc(len * sizeof(char)); 330 full_path = malloc(len * sizeof(char));
323 if (!full_path) { 331 if (!full_path) {
324 sway_log(L_ERROR, "Unable to allocate full path to included config"); 332 sway_log(L_ERROR,
333 "Unable to allocate full path to included config");
325 return false; 334 return false;
326 } 335 }
327 snprintf(full_path, len, "%s/%s", parent_dir, path); 336 snprintf(full_path, len, "%s/%s", parent_dir, path);
@@ -340,7 +349,9 @@ static bool load_include_config(const char *path, const char *parent_dir, struct
340 for (j = 0; j < config->config_chain->length; ++j) { 349 for (j = 0; j < config->config_chain->length; ++j) {
341 char *old_path = config->config_chain->items[j]; 350 char *old_path = config->config_chain->items[j];
342 if (strcmp(real_path, old_path) == 0) { 351 if (strcmp(real_path, old_path) == 0) {
343 sway_log(L_DEBUG, "%s already included once, won't be included again.", real_path); 352 sway_log(L_DEBUG,
353 "%s already included once, won't be included again.",
354 real_path);
344 free(real_path); 355 free(real_path);
345 return false; 356 return false;
346 } 357 }
@@ -400,6 +411,7 @@ bool load_include_configs(const char *path, struct sway_config *config) {
400 return true; 411 return true;
401} 412}
402 413
414
403bool read_config(FILE *file, struct sway_config *config) { 415bool read_config(FILE *file, struct sway_config *config) {
404 bool success = true; 416 bool success = true;
405 enum cmd_status block = CMD_BLOCK_END; 417 enum cmd_status block = CMD_BLOCK_END;
@@ -427,8 +439,8 @@ bool read_config(FILE *file, struct sway_config *config) {
427 switch(res->status) { 439 switch(res->status) {
428 case CMD_FAILURE: 440 case CMD_FAILURE:
429 case CMD_INVALID: 441 case CMD_INVALID:
430 sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, line, 442 sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number,
431 res->error, config->current_config); 443 line, res->error, config->current_config);
432 success = false; 444 success = false;
433 break; 445 break;
434 446
@@ -453,6 +465,14 @@ bool read_config(FILE *file, struct sway_config *config) {
453 } 465 }
454 break; 466 break;
455 467
468 case CMD_BLOCK_SEAT:
469 if (block == CMD_BLOCK_END) {
470 block = CMD_BLOCK_SEAT;
471 } else {
472 sway_log(L_ERROR, "Invalid block '%s'", line);
473 }
474 break;
475
456 case CMD_BLOCK_BAR: 476 case CMD_BLOCK_BAR:
457 if (block == CMD_BLOCK_END) { 477 if (block == CMD_BLOCK_END) {
458 block = CMD_BLOCK_BAR; 478 block = CMD_BLOCK_BAR;
@@ -503,8 +523,13 @@ bool read_config(FILE *file, struct sway_config *config) {
503 523
504 case CMD_BLOCK_INPUT: 524 case CMD_BLOCK_INPUT:
505 sway_log(L_DEBUG, "End of input block"); 525 sway_log(L_DEBUG, "End of input block");
506 // TODO: input 526 current_input_config = NULL;
507 //current_input_config = NULL; 527 block = CMD_BLOCK_END;
528 break;
529
530 case CMD_BLOCK_SEAT:
531 sway_log(L_DEBUG, "End of seat block");
532 current_seat_config = NULL;
508 block = CMD_BLOCK_END; 533 block = CMD_BLOCK_END;
509 break; 534 break;
510 535
@@ -569,7 +594,8 @@ char *do_var_replacement(char *str) {
569 char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); 594 char *newstr = malloc(strlen(str) - vnlen + vvlen + 1);
570 if (!newstr) { 595 if (!newstr) {
571 sway_log(L_ERROR, 596 sway_log(L_ERROR,
572 "Unable to allocate replacement during variable expansion"); 597 "Unable to allocate replacement "
598 "during variable expansion");
573 break; 599 break;
574 } 600 }
575 char *newptr = newstr; 601 char *newptr = newstr;
diff --git a/sway/config/input.c b/sway/config/input.c
new file mode 100644
index 00000000..6f8d31f7
--- /dev/null
+++ b/sway/config/input.c
@@ -0,0 +1,105 @@
1#define _XOPEN_SOURCE 700
2#include <stdlib.h>
3#include <limits.h>
4#include <float.h>
5#include "sway/config.h"
6#include "log.h"
7
8struct input_config *new_input_config(const char* identifier) {
9 struct input_config *input = calloc(1, sizeof(struct input_config));
10 if (!input) {
11 sway_log(L_DEBUG, "Unable to allocate input config");
12 return NULL;
13 }
14 sway_log(L_DEBUG, "new_input_config(%s)", identifier);
15 if (!(input->identifier = strdup(identifier))) {
16 free(input);
17 sway_log(L_DEBUG, "Unable to allocate input config");
18 return NULL;
19 }
20
21 input->tap = INT_MIN;
22 input->drag_lock = INT_MIN;
23 input->dwt = INT_MIN;
24 input->send_events = INT_MIN;
25 input->click_method = INT_MIN;
26 input->middle_emulation = INT_MIN;
27 input->natural_scroll = INT_MIN;
28 input->accel_profile = INT_MIN;
29 input->pointer_accel = FLT_MIN;
30 input->scroll_method = INT_MIN;
31 input->left_handed = INT_MIN;
32
33 return input;
34}
35
36void merge_input_config(struct input_config *dst, struct input_config *src) {
37 if (src->identifier) {
38 free(dst->identifier);
39 dst->identifier = strdup(src->identifier);
40 }
41 if (src->accel_profile != INT_MIN) {
42 dst->accel_profile = src->accel_profile;
43 }
44 if (src->click_method != INT_MIN) {
45 dst->click_method = src->click_method;
46 }
47 if (src->drag_lock != INT_MIN) {
48 dst->drag_lock = src->drag_lock;
49 }
50 if (src->dwt != INT_MIN) {
51 dst->dwt = src->dwt;
52 }
53 if (src->middle_emulation != INT_MIN) {
54 dst->middle_emulation = src->middle_emulation;
55 }
56 if (src->natural_scroll != INT_MIN) {
57 dst->natural_scroll = src->natural_scroll;
58 }
59 if (src->pointer_accel != FLT_MIN) {
60 dst->pointer_accel = src->pointer_accel;
61 }
62 if (src->scroll_method != INT_MIN) {
63 dst->scroll_method = src->scroll_method;
64 }
65 if (src->send_events != INT_MIN) {
66 dst->send_events = src->send_events;
67 }
68 if (src->tap != INT_MIN) {
69 dst->tap = src->tap;
70 }
71 if (src->xkb_layout) {
72 free(dst->xkb_layout);
73 dst->xkb_layout = strdup(src->xkb_layout);
74 }
75 if (src->xkb_model) {
76 free(dst->xkb_model);
77 dst->xkb_model = strdup(src->xkb_model);
78 }
79 if (src->xkb_options) {
80 free(dst->xkb_options);
81 dst->xkb_options = strdup(src->xkb_options);
82 }
83 if (src->xkb_rules) {
84 free(dst->xkb_rules);
85 dst->xkb_rules = strdup(src->xkb_rules);
86 }
87 if (src->xkb_variant) {
88 free(dst->xkb_variant);
89 dst->xkb_variant = strdup(src->xkb_variant);
90 }
91}
92
93void free_input_config(struct input_config *ic) {
94 if (!ic) {
95 return;
96 }
97 free(ic->identifier);
98 free(ic);
99}
100
101int input_identifier_cmp(const void *item, const void *data) {
102 const struct input_config *ic = item;
103 const char *identifier = data;
104 return strcmp(ic->identifier, identifier);
105}
diff --git a/sway/config/seat.c b/sway/config/seat.c
new file mode 100644
index 00000000..113139e8
--- /dev/null
+++ b/sway/config/seat.c
@@ -0,0 +1,135 @@
1#define _XOPEN_SOURCE 700
2#include <stdlib.h>
3#include <string.h>
4#include "sway/config.h"
5#include "log.h"
6
7struct seat_config *new_seat_config(const char* name) {
8 struct seat_config *seat = calloc(1, sizeof(struct seat_config));
9 if (!seat) {
10 sway_log(L_DEBUG, "Unable to allocate seat config");
11 return NULL;
12 }
13
14 sway_log(L_DEBUG, "new_seat_config(%s)", name);
15 seat->name = strdup(name);
16 if (!sway_assert(seat->name, "could not allocate name for seat")) {
17 free(seat);
18 return NULL;
19 }
20
21 seat->fallback = -1;
22 seat->attachments = create_list();
23 if (!sway_assert(seat->attachments,
24 "could not allocate seat attachments list")) {
25 free(seat->name);
26 free(seat);
27 return NULL;
28 }
29
30 return seat;
31}
32
33struct seat_attachment_config *seat_attachment_config_new() {
34 struct seat_attachment_config *attachment =
35 calloc(1, sizeof(struct seat_attachment_config));
36 if (!attachment) {
37 sway_log(L_DEBUG, "cannot allocate attachment config");
38 return NULL;
39 }
40 return attachment;
41}
42
43static void seat_attachment_config_free(
44 struct seat_attachment_config *attachment) {
45 free(attachment->identifier);
46 free(attachment);
47 return;
48}
49
50static struct seat_attachment_config *seat_attachment_config_copy(
51 struct seat_attachment_config *attachment) {
52 struct seat_attachment_config *copy = seat_attachment_config_new();
53 if (!copy) {
54 return NULL;
55 }
56
57 copy->identifier = strdup(attachment->identifier);
58
59 return copy;
60}
61
62static void merge_seat_attachment_config(struct seat_attachment_config *dest,
63 struct seat_attachment_config *source) {
64 // nothing to merge yet, but there will be some day
65}
66
67void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
68 if (source->name) {
69 free(dest->name);
70 dest->name = strdup(source->name);
71 }
72
73 if (source->fallback != -1) {
74 dest->fallback = source->fallback;
75 }
76
77 for (int i = 0; i < source->attachments->length; ++i) {
78 struct seat_attachment_config *source_attachment =
79 source->attachments->items[i];
80 bool found = false;
81 for (int j = 0; j < dest->attachments->length; ++j) {
82 struct seat_attachment_config *dest_attachment =
83 dest->attachments->items[j];
84 if (strcmp(source_attachment->identifier,
85 dest_attachment->identifier) == 0) {
86 merge_seat_attachment_config(dest_attachment,
87 source_attachment);
88 found = true;
89 }
90 }
91
92 if (!found) {
93 struct seat_attachment_config *copy =
94 seat_attachment_config_copy(source_attachment);
95 if (copy) {
96 list_add(dest->attachments, copy);
97 }
98 }
99 }
100}
101
102void free_seat_config(struct seat_config *seat) {
103 if (!seat) {
104 return;
105 }
106
107 free(seat->name);
108 for (int i = 0; i < seat->attachments->length; ++i) {
109 struct seat_attachment_config *attachment =
110 seat->attachments->items[i];
111 seat_attachment_config_free(attachment);
112 }
113
114 list_free(seat->attachments);
115 free(seat);
116}
117
118int seat_name_cmp(const void *item, const void *data) {
119 const struct seat_config *sc = item;
120 const char *name = data;
121 return strcmp(sc->name, name);
122}
123
124struct seat_attachment_config *seat_config_get_attachment(
125 struct seat_config *seat_config, char *identifier) {
126 for (int i = 0; i < seat_config->attachments->length; ++i) {
127 struct seat_attachment_config *attachment =
128 seat_config->attachments->items[i];
129 if (strcmp(attachment->identifier, identifier) == 0) {
130 return attachment;
131 }
132 }
133
134 return NULL;
135}
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..e7150bf3 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) {
@@ -53,8 +55,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
53 struct sway_wl_shell_surface *sway_surface = 55 struct sway_wl_shell_surface *sway_surface =
54 wl_container_of(listener, sway_surface, commit); 56 wl_container_of(listener, sway_surface, commit);
55 struct sway_view *view = sway_surface->view; 57 struct sway_view *view = sway_surface->view;
56 sway_log(L_DEBUG, "wl_shell surface commit %dx%d",
57 sway_surface->pending_width, sway_surface->pending_height);
58 // NOTE: We intentionally discard the view's desired width here 58 // NOTE: We intentionally discard the view's desired width here
59 // TODO: Let floating views do whatever 59 // TODO: Let floating views do whatever
60 view->width = sway_surface->pending_width; 60 view->width = sway_surface->pending_width;
@@ -126,4 +126,6 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
126 sway_view->swayc = cont; 126 sway_view->swayc = cont;
127 127
128 arrange_windows(cont->parent, -1, -1); 128 arrange_windows(cont->parent, -1, -1);
129
130 sway_input_manager_set_focus(input_manager, cont);
129} 131}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 2435c256..015cc9d0 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) {
@@ -59,8 +61,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
59 struct sway_xdg_surface_v6 *sway_surface = 61 struct sway_xdg_surface_v6 *sway_surface =
60 wl_container_of(listener, sway_surface, commit); 62 wl_container_of(listener, sway_surface, commit);
61 struct sway_view *view = sway_surface->view; 63 struct sway_view *view = sway_surface->view;
62 sway_log(L_DEBUG, "xdg surface commit %dx%d",
63 sway_surface->pending_width, sway_surface->pending_height);
64 // NOTE: We intentionally discard the view's desired width here 64 // NOTE: We intentionally discard the view's desired width here
65 // TODO: Let floating views do whatever 65 // TODO: Let floating views do whatever
66 view->width = sway_surface->pending_width; 66 view->width = sway_surface->pending_width;
@@ -132,4 +132,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
132 sway_view->swayc = cont; 132 sway_view->swayc = cont;
133 133
134 arrange_windows(cont->parent, -1, -1); 134 arrange_windows(cont->parent, -1, -1);
135
136 sway_input_manager_set_focus(input_manager, cont);
135} 137}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index e3799d2d..42e82c64 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) {
@@ -82,8 +84,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
82 struct sway_xwayland_surface *sway_surface = 84 struct sway_xwayland_surface *sway_surface =
83 wl_container_of(listener, sway_surface, commit); 85 wl_container_of(listener, sway_surface, commit);
84 struct sway_view *view = sway_surface->view; 86 struct sway_view *view = sway_surface->view;
85 sway_log(L_DEBUG, "xwayland surface commit %dx%d",
86 sway_surface->pending_width, sway_surface->pending_height);
87 // NOTE: We intentionally discard the view's desired width here 87 // NOTE: We intentionally discard the view's desired width here
88 // TODO: Let floating views do whatever 88 // TODO: Let floating views do whatever
89 view->width = sway_surface->pending_width; 89 view->width = sway_surface->pending_width;
@@ -171,4 +171,5 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
171 sway_view->swayc = cont; 171 sway_view->swayc = cont;
172 172
173 arrange_windows(cont->parent, -1, -1); 173 arrange_windows(cont->parent, -1, -1);
174 sway_input_manager_set_focus(input_manager, cont);
174} 175}
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
new file mode 100644
index 00000000..3b5cfce5
--- /dev/null
+++ b/sway/input/cursor.c
@@ -0,0 +1,181 @@
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 cursor->x = x;
19 cursor->y = y;
20}
21
22static void cursor_send_pointer_motion(struct sway_cursor *cursor,
23 uint32_t time) {
24 struct wlr_seat *seat = cursor->seat->wlr_seat;
25 struct wlr_surface *surface = NULL;
26 double sx, sy;
27 swayc_t *swayc =
28 swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy);
29 if (swayc) {
30 wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
31 wlr_seat_pointer_notify_motion(seat, time, sx, sy);
32 } else {
33 wlr_seat_pointer_clear_focus(seat);
34 }
35}
36
37static void handle_cursor_motion(struct wl_listener *listener, void *data) {
38 struct sway_cursor *cursor =
39 wl_container_of(listener, cursor, motion);
40 struct wlr_event_pointer_motion *event = data;
41 wlr_cursor_move(cursor->cursor, event->device,
42 event->delta_x, event->delta_y);
43 cursor_update_position(cursor);
44 cursor_send_pointer_motion(cursor, event->time_msec);
45}
46
47static void handle_cursor_motion_absolute(struct wl_listener *listener,
48 void *data) {
49 struct sway_cursor *cursor =
50 wl_container_of(listener, cursor, motion_absolute);
51 struct wlr_event_pointer_motion_absolute *event = data;
52 wlr_cursor_warp_absolute(cursor->cursor, event->device,
53 event->x_mm / event->width_mm, event->y_mm / event->height_mm);
54 cursor_update_position(cursor);
55 cursor_send_pointer_motion(cursor, event->time_msec);
56}
57
58static void handle_cursor_button(struct wl_listener *listener, void *data) {
59 struct sway_cursor *cursor =
60 wl_container_of(listener, cursor, button);
61 struct wlr_event_pointer_button *event = data;
62
63 if (event->button == BTN_LEFT) {
64 struct wlr_surface *surface = NULL;
65 double sx, sy;
66 swayc_t *swayc =
67 swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy);
68
69 sway_seat_set_focus(cursor->seat, swayc);
70 }
71
72 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec,
73 event->button, event->state);
74}
75
76static void handle_cursor_axis(struct wl_listener *listener, void *data) {
77 struct sway_cursor *cursor =
78 wl_container_of(listener, cursor, axis);
79 struct wlr_event_pointer_axis *event = data;
80 wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
81 event->orientation, event->delta);
82}
83
84static void handle_touch_down(struct wl_listener *listener, void *data) {
85 struct sway_cursor *cursor =
86 wl_container_of(listener, cursor, touch_down);
87 struct wlr_event_touch_down *event = data;
88 sway_log(L_DEBUG, "TODO: handle touch down event: %p", event);
89}
90
91static void handle_touch_up(struct wl_listener *listener, void *data) {
92 struct sway_cursor *cursor =
93 wl_container_of(listener, cursor, touch_up);
94 struct wlr_event_touch_up *event = data;
95 sway_log(L_DEBUG, "TODO: handle touch up event: %p", event);
96}
97
98static void handle_touch_motion(struct wl_listener *listener, void *data) {
99 struct sway_cursor *cursor =
100 wl_container_of(listener, cursor, touch_motion);
101 struct wlr_event_touch_motion *event = data;
102 sway_log(L_DEBUG, "TODO: handle touch motion event: %p", event);
103}
104
105static void handle_tool_axis(struct wl_listener *listener, void *data) {
106 struct sway_cursor *cursor =
107 wl_container_of(listener, cursor, tool_axis);
108 struct wlr_event_tablet_tool_axis *event = data;
109 sway_log(L_DEBUG, "TODO: handle tool axis event: %p", event);
110}
111
112static void handle_tool_tip(struct wl_listener *listener, void *data) {
113 struct sway_cursor *cursor =
114 wl_container_of(listener, cursor, tool_tip);
115 struct wlr_event_tablet_tool_tip *event = data;
116 sway_log(L_DEBUG, "TODO: handle tool tip event: %p", event);
117}
118
119static void handle_request_set_cursor(struct wl_listener *listener,
120 void *data) {
121 struct sway_cursor *cursor =
122 wl_container_of(listener, cursor, request_set_cursor);
123 struct wlr_seat_pointer_request_set_cursor_event *event = data;
124 sway_log(L_DEBUG, "TODO: handle request set cursor event: %p", event);
125}
126
127struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
128 struct sway_cursor *cursor = calloc(1, sizeof(struct sway_cursor));
129 if (!sway_assert(cursor, "could not allocate sway cursor")) {
130 return NULL;
131 }
132
133 struct wlr_cursor *wlr_cursor = wlr_cursor_create();
134 if (!sway_assert(wlr_cursor, "could not allocate wlr cursor")) {
135 free(cursor);
136 return NULL;
137 }
138
139 cursor->seat = seat;
140 wlr_cursor_attach_output_layout(wlr_cursor,
141 root_container.sway_root->output_layout);
142
143 // input events
144 wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
145 cursor->motion.notify = handle_cursor_motion;
146
147 wl_signal_add(&wlr_cursor->events.motion_absolute,
148 &cursor->motion_absolute);
149 cursor->motion_absolute.notify = handle_cursor_motion_absolute;
150
151 wl_signal_add(&wlr_cursor->events.button, &cursor->button);
152 cursor->button.notify = handle_cursor_button;
153
154 wl_signal_add(&wlr_cursor->events.axis, &cursor->axis);
155 cursor->axis.notify = handle_cursor_axis;
156
157 wl_signal_add(&wlr_cursor->events.touch_down, &cursor->touch_down);
158 cursor->touch_down.notify = handle_touch_down;
159
160 wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up);
161 cursor->touch_up.notify = handle_touch_up;
162
163 wl_signal_add(&wlr_cursor->events.touch_motion,
164 &cursor->touch_motion);
165 cursor->touch_motion.notify = handle_touch_motion;
166
167 wl_signal_add(&wlr_cursor->events.tablet_tool_axis,
168 &cursor->tool_axis);
169 cursor->tool_axis.notify = handle_tool_axis;
170
171 wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip);
172 cursor->tool_tip.notify = handle_tool_tip;
173
174 wl_signal_add(&seat->wlr_seat->events.request_set_cursor,
175 &cursor->request_set_cursor);
176 cursor->request_set_cursor.notify = handle_request_set_cursor;
177
178 cursor->cursor = wlr_cursor;
179
180 return cursor;
181}
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
new file mode 100644
index 00000000..4459c43b
--- /dev/null
+++ b/sway/input/input-manager.c
@@ -0,0 +1,293 @@
1#define _XOPEN_SOURCE 700
2#include <ctype.h>
3#include <float.h>
4#include <limits.h>
5#include <stdio.h>
6#include <string.h>
7#include <libinput.h>
8#include <math.h>
9#include "sway/config.h"
10#include "sway/input/input-manager.h"
11#include "sway/input/seat.h"
12#include "sway/server.h"
13#include "stringop.h"
14#include "list.h"
15#include "log.h"
16
17static const char *default_seat = "seat0";
18
19// TODO make me not global
20struct sway_input_manager *input_manager;
21
22struct input_config *current_input_config = NULL;
23struct seat_config *current_seat_config = NULL;
24
25static struct sway_seat *input_manager_get_seat(
26 struct sway_input_manager *input, const char *seat_name) {
27 struct sway_seat *seat = NULL;
28 wl_list_for_each(seat, &input->seats, link) {
29 if (strcmp(seat->wlr_seat->name, seat_name) == 0) {
30 return seat;
31 }
32 }
33
34 return sway_seat_create(input, seat_name);
35}
36
37static char *get_device_identifier(struct wlr_input_device *device) {
38 int vendor = device->vendor;
39 int product = device->product;
40 char *name = strdup(device->name);
41 name = strip_whitespace(name);
42
43 char *p = name;
44 for (; *p; ++p) {
45 if (*p == ' ') {
46 *p = '_';
47 }
48 }
49
50 const char *fmt = "%d:%d:%s";
51 int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1;
52 char *identifier = malloc(len);
53 if (!identifier) {
54 sway_log(L_ERROR, "Unable to allocate unique input device name");
55 return NULL;
56 }
57
58 snprintf(identifier, len, fmt, vendor, product, name);
59 free(name);
60 return identifier;
61}
62
63static struct sway_input_device *input_sway_device_from_wlr(
64 struct sway_input_manager *input, struct wlr_input_device *device) {
65 struct sway_input_device *input_device = NULL;
66 wl_list_for_each(input_device, &input->devices, link) {
67 if (input_device->wlr_device == device) {
68 return input_device;
69 }
70 }
71 return NULL;
72}
73
74static bool input_has_seat_configuration(struct sway_input_manager *input) {
75 struct sway_seat *seat = NULL;
76 wl_list_for_each(seat, &input->seats, link) {
77 if (seat->config) {
78 return true;
79 }
80 }
81
82 return false;
83}
84
85static void input_add_notify(struct wl_listener *listener, void *data) {
86 struct sway_input_manager *input =
87 wl_container_of(listener, input, input_add);
88 struct wlr_input_device *device = data;
89
90 struct sway_input_device *input_device =
91 calloc(1, sizeof(struct sway_input_device));
92 if (!sway_assert(input_device, "could not allocate input device")) {
93 return;
94 }
95
96 input_device->wlr_device = device;
97 input_device->identifier = get_device_identifier(device);
98 wl_list_insert(&input->devices, &input_device->link);
99
100 sway_log(L_DEBUG, "adding device: '%s'",
101 input_device->identifier);
102
103 // find config
104 for (int i = 0; i < config->input_configs->length; ++i) {
105 struct input_config *input_config = config->input_configs->items[i];
106 if (strcmp(input_config->identifier, input_device->identifier) == 0) {
107 input_device->config = input_config;
108 break;
109 }
110 }
111
112 struct sway_seat *seat = NULL;
113 if (!input_has_seat_configuration(input)) {
114 sway_log(L_DEBUG, "no seat configuration, using default seat");
115 seat = input_manager_get_seat(input, default_seat);
116 sway_seat_add_device(seat, input_device);
117 return;
118 }
119
120 bool added = false;
121 wl_list_for_each(seat, &input->seats, link) {
122 bool has_attachment = seat->config &&
123 (seat_config_get_attachment(seat->config, input_device->identifier) ||
124 seat_config_get_attachment(seat->config, "*"));
125
126 if (has_attachment) {
127 sway_seat_add_device(seat, input_device);
128 added = true;
129 }
130 }
131
132 if (!added) {
133 wl_list_for_each(seat, &input->seats, link) {
134 if (seat->config && seat->config->fallback == 1) {
135 sway_seat_add_device(seat, input_device);
136 added = true;
137 }
138 }
139 }
140
141 if (!added) {
142 sway_log(L_DEBUG,
143 "device '%s' is not configured on any seats",
144 input_device->identifier);
145 }
146}
147
148static void input_remove_notify(struct wl_listener *listener, void *data) {
149 struct sway_input_manager *input =
150 wl_container_of(listener, input, input_remove);
151 struct wlr_input_device *device = data;
152
153 struct sway_input_device *input_device =
154 input_sway_device_from_wlr(input, device);
155
156 if (!sway_assert(input_device, "could not find sway device")) {
157 return;
158 }
159
160 sway_log(L_DEBUG, "removing device: '%s'",
161 input_device->identifier);
162
163 struct sway_seat *seat = NULL;
164 wl_list_for_each(seat, &input->seats, link) {
165 sway_seat_remove_device(seat, input_device);
166 }
167
168 wl_list_remove(&input_device->link);
169 free(input_device->identifier);
170 free(input_device);
171}
172
173struct sway_input_manager *sway_input_manager_create(
174 struct sway_server *server) {
175 struct sway_input_manager *input =
176 calloc(1, sizeof(struct sway_input_manager));
177 if (!input) {
178 return NULL;
179 }
180 input->server = server;
181
182 wl_list_init(&input->devices);
183 wl_list_init(&input->seats);
184
185 // create the default seat
186 input_manager_get_seat(input, default_seat);
187
188 input->input_add.notify = input_add_notify;
189 wl_signal_add(&server->backend->events.input_add, &input->input_add);
190
191 input->input_remove.notify = input_remove_notify;
192 wl_signal_add(&server->backend->events.input_remove, &input->input_remove);
193
194 return input;
195}
196
197bool sway_input_manager_has_focus(struct sway_input_manager *input,
198 swayc_t *container) {
199 struct sway_seat *seat = NULL;
200 wl_list_for_each(seat, &input->seats, link) {
201 if (seat->focus == container) {
202 return true;
203 }
204 }
205
206 return false;
207}
208
209void sway_input_manager_set_focus(struct sway_input_manager *input,
210 swayc_t *container) {
211 struct sway_seat *seat ;
212 wl_list_for_each(seat, &input->seats, link) {
213 sway_seat_set_focus(seat, container);
214 }
215}
216
217void sway_input_manager_apply_input_config(struct sway_input_manager *input,
218 struct input_config *input_config) {
219 struct sway_input_device *input_device = NULL;
220 wl_list_for_each(input_device, &input->devices, link) {
221 if (strcmp(input_device->identifier, input_config->identifier) == 0) {
222 input_device->config = input_config;
223
224 struct sway_seat *seat = NULL;
225 wl_list_for_each(seat, &input->seats, link) {
226 sway_seat_configure_device(seat, input_device);
227 }
228 }
229 }
230}
231
232void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
233 struct seat_config *seat_config) {
234 sway_log(L_DEBUG, "applying new seat config for seat %s",
235 seat_config->name);
236 struct sway_seat *seat = input_manager_get_seat(input, seat_config->name);
237 if (!seat) {
238 return;
239 }
240
241 sway_seat_set_config(seat, seat_config);
242
243 // for every device, try to add it to a seat and if no seat has it
244 // attached, add it to the fallback seats.
245 struct sway_input_device *input_device = NULL;
246 wl_list_for_each(input_device, &input->devices, link) {
247 list_t *seat_list = create_list();
248 struct sway_seat *seat = NULL;
249 wl_list_for_each(seat, &input->seats, link) {
250 if (!seat->config) {
251 continue;
252 }
253 if (seat_config_get_attachment(seat->config, "*") ||
254 seat_config_get_attachment(seat->config,
255 input_device->identifier)) {
256 list_add(seat_list, seat);
257 }
258 }
259
260 if (seat_list->length) {
261 wl_list_for_each(seat, &input->seats, link) {
262 bool attached = false;
263 for (int i = 0; i < seat_list->length; ++i) {
264 if (seat == seat_list->items[i]) {
265 attached = true;
266 break;
267 }
268 }
269 if (attached) {
270 sway_seat_add_device(seat, input_device);
271 } else {
272 sway_seat_remove_device(seat, input_device);
273 }
274 }
275 } else {
276 wl_list_for_each(seat, &input->seats, link) {
277 if (seat->config && seat->config->fallback == 1) {
278 sway_seat_add_device(seat, input_device);
279 } else {
280 sway_seat_remove_device(seat, input_device);
281 }
282 }
283 }
284 list_free(seat_list);
285 }
286}
287
288void sway_input_manager_configure_xcursor(struct sway_input_manager *input) {
289 struct sway_seat *seat = NULL;
290 wl_list_for_each(seat, &input->seats, link) {
291 sway_seat_configure_xcursor(seat);
292 }
293}
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..724941d8
--- /dev/null
+++ b/sway/input/keyboard.c
@@ -0,0 +1,123 @@
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 struct xkb_keymap *keymap =
89 xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
90
91 if (!keymap) {
92 sway_log(L_DEBUG, "cannot configure keyboard: keymap does not exist");
93 xkb_context_unref(context);
94 return;
95 }
96
97 xkb_keymap_unref(keyboard->keymap);
98 keyboard->keymap = keymap;
99 wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap);
100
101 wlr_keyboard_set_repeat_info(wlr_device->keyboard, 25, 600);
102 xkb_context_unref(context);
103 struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
104 wlr_seat_set_keyboard(seat, wlr_device);
105
106 wl_list_remove(&keyboard->keyboard_key.link);
107 wl_signal_add(&wlr_device->keyboard->events.key, &keyboard->keyboard_key);
108 keyboard->keyboard_key.notify = handle_keyboard_key;
109
110 wl_list_remove(&keyboard->keyboard_modifiers.link);
111 wl_signal_add( &wlr_device->keyboard->events.modifiers,
112 &keyboard->keyboard_modifiers);
113 keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
114}
115
116void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
117 if (!keyboard) {
118 return;
119 }
120 wl_list_remove(&keyboard->keyboard_key.link);
121 wl_list_remove(&keyboard->keyboard_modifiers.link);
122 free(keyboard);
123}
diff --git a/sway/input/seat.c b/sway/input/seat.c
new file mode 100644
index 00000000..fe90565a
--- /dev/null
+++ b/sway/input/seat.c
@@ -0,0 +1,253 @@
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 free(seat);
34 return NULL;
35 }
36
37 seat->cursor = sway_cursor_create(seat);
38 if (!seat->cursor) {
39 wlr_seat_destroy(seat->wlr_seat);
40 free(seat);
41 return NULL;
42 }
43
44 seat->input = input;
45 wl_list_init(&seat->devices);
46
47 wlr_seat_set_capabilities(seat->wlr_seat,
48 WL_SEAT_CAPABILITY_KEYBOARD |
49 WL_SEAT_CAPABILITY_POINTER |
50 WL_SEAT_CAPABILITY_TOUCH);
51
52 sway_seat_configure_xcursor(seat);
53
54 wl_list_insert(&input->seats, &seat->link);
55
56 return seat;
57}
58
59static void seat_configure_pointer(struct sway_seat *seat,
60 struct sway_seat_device *sway_device) {
61 // TODO pointer configuration
62 wlr_cursor_attach_input_device(seat->cursor->cursor,
63 sway_device->input_device->wlr_device);
64}
65
66static void seat_configure_keyboard(struct sway_seat *seat,
67 struct sway_seat_device *seat_device) {
68 if (!seat_device->keyboard) {
69 sway_keyboard_create(seat, seat_device);
70 }
71 sway_keyboard_configure(seat_device->keyboard);
72 wlr_seat_set_keyboard(seat->wlr_seat,
73 seat_device->input_device->wlr_device);
74 if (seat->focus) {
75 // force notify reenter to pick up the new configuration
76 wlr_seat_keyboard_clear_focus(seat->wlr_seat);
77 wlr_seat_keyboard_notify_enter(seat->wlr_seat, seat->focus->sway_view->surface);
78 }
79}
80
81static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat,
82 struct sway_input_device *input_device) {
83 struct sway_seat_device *seat_device = NULL;
84 wl_list_for_each(seat_device, &seat->devices, link) {
85 if (seat_device->input_device == input_device) {
86 return seat_device;
87 }
88 }
89
90 return NULL;
91}
92
93void sway_seat_configure_device(struct sway_seat *seat,
94 struct sway_input_device *input_device) {
95 struct sway_seat_device *seat_device =
96 sway_seat_get_device(seat, input_device);
97 if (!seat_device) {
98 return;
99 }
100
101 if (seat->config) {
102 seat_device->attachment_config =
103 seat_config_get_attachment(seat->config, input_device->identifier);
104 }
105
106 switch (input_device->wlr_device->type) {
107 case WLR_INPUT_DEVICE_POINTER:
108 seat_configure_pointer(seat, seat_device);
109 break;
110 case WLR_INPUT_DEVICE_KEYBOARD:
111 seat_configure_keyboard(seat, seat_device);
112 break;
113 case WLR_INPUT_DEVICE_TOUCH:
114 case WLR_INPUT_DEVICE_TABLET_PAD:
115 case WLR_INPUT_DEVICE_TABLET_TOOL:
116 sway_log(L_DEBUG, "TODO: configure other devices");
117 break;
118 }
119}
120
121void sway_seat_add_device(struct sway_seat *seat,
122 struct sway_input_device *input_device) {
123 if (sway_seat_get_device(seat, input_device)) {
124 sway_seat_configure_device(seat, input_device);
125 return;
126 }
127
128 struct sway_seat_device *seat_device =
129 calloc(1, sizeof(struct sway_seat_device));
130 if (!seat_device) {
131 sway_log(L_DEBUG, "could not allocate seat device");
132 return;
133 }
134
135 sway_log(L_DEBUG, "adding device %s to seat %s",
136 input_device->identifier, seat->wlr_seat->name);
137
138 seat_device->sway_seat = seat;
139 seat_device->input_device = input_device;
140 wl_list_insert(&seat->devices, &seat_device->link);
141
142 sway_seat_configure_device(seat, input_device);
143}
144
145void sway_seat_remove_device(struct sway_seat *seat,
146 struct sway_input_device *input_device) {
147 struct sway_seat_device *seat_device =
148 sway_seat_get_device(seat, input_device);
149
150 if (!seat_device) {
151 return;
152 }
153
154 sway_log(L_DEBUG, "removing device %s from seat %s",
155 input_device->identifier, seat->wlr_seat->name);
156
157 seat_device_destroy(seat_device);
158}
159
160void sway_seat_configure_xcursor(struct sway_seat *seat) {
161 // TODO configure theme and size
162 const char *cursor_theme = "default";
163
164 if (!seat->cursor->xcursor_manager) {
165 seat->cursor->xcursor_manager =
166 wlr_xcursor_manager_create("default", 24);
167 if (sway_assert(seat->cursor->xcursor_manager,
168 "Cannot create XCursor manager for theme %s",
169 cursor_theme)) {
170 return;
171 }
172 }
173
174 for (int i = 0; i < root_container.children->length; ++i) {
175 swayc_t *output_container = root_container.children->items[i];
176 struct wlr_output *output =
177 output_container->sway_output->wlr_output;
178 bool result =
179 wlr_xcursor_manager_load(seat->cursor->xcursor_manager,
180 output->scale);
181
182 sway_assert(!result,
183 "Cannot load xcursor theme for output '%s' with scale %f",
184 // TODO: Fractional scaling
185 output->name, (double)output->scale);
186 }
187
188 wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager,
189 "left_ptr", seat->cursor->cursor);
190 wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x,
191 seat->cursor->cursor->y);
192}
193
194static void handle_focus_destroy(struct wl_listener *listener, void *data) {
195 struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy);
196 //swayc_t *container = data;
197
198 // TODO set new focus based on the state of the tree
199 sway_seat_set_focus(seat, NULL);
200}
201
202void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
203 swayc_t *last_focus = seat->focus;
204
205 if (last_focus == container) {
206 return;
207 }
208
209 if (last_focus) {
210 wl_list_remove(&seat->focus_destroy.link);
211 }
212
213 if (container) {
214 struct sway_view *view = container->sway_view;
215 view->iface.set_activated(view, true);
216 wl_signal_add(&container->events.destroy, &seat->focus_destroy);
217 seat->focus_destroy.notify = handle_focus_destroy;
218 wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface);
219 }
220
221 seat->focus = container;
222
223 if (last_focus &&
224 !sway_input_manager_has_focus(seat->input, last_focus)) {
225 struct sway_view *view = last_focus->sway_view;
226 view->iface.set_activated(view, false);
227
228 }
229}
230
231void sway_seat_set_config(struct sway_seat *seat,
232 struct seat_config *seat_config) {
233 // clear configs
234 seat->config = NULL;
235
236 struct sway_seat_device *seat_device = NULL;
237 wl_list_for_each(seat_device, &seat->devices, link) {
238 seat_device->attachment_config = NULL;
239 }
240
241 if (!seat_config) {
242 return;
243 }
244
245 // add configs
246 seat->config = seat_config;
247
248 wl_list_for_each(seat_device, &seat->devices, link) {
249 seat_device->attachment_config =
250 seat_config_get_attachment(seat_config,
251 seat_device->input_device->identifier);
252 }
253}
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 09a32c1b..bab9a201 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -141,3 +141,40 @@ json_object *ipc_json_describe_container_recursive(swayc_t *c) {
141 141
142 return object; 142 return object;
143} 143}
144
145static const char *describe_device_type(struct sway_input_device *device) {
146 switch (device->wlr_device->type) {
147 case WLR_INPUT_DEVICE_POINTER:
148 return "pointer";
149 case WLR_INPUT_DEVICE_KEYBOARD:
150 return "keyboard";
151 case WLR_INPUT_DEVICE_TOUCH:
152 return "touch";
153 case WLR_INPUT_DEVICE_TABLET_TOOL:
154 return "tablet_tool";
155 case WLR_INPUT_DEVICE_TABLET_PAD:
156 return "tablet_pad";
157 }
158 return "unknown";
159}
160
161json_object *ipc_json_describe_input(struct sway_input_device *device) {
162 if (!(sway_assert(device, "Device must not be null"))) {
163 return NULL;
164 }
165
166 json_object *object = json_object_new_object();
167
168 json_object_object_add(object, "identifier",
169 json_object_new_string(device->identifier));
170 json_object_object_add(object, "name",
171 json_object_new_string(device->wlr_device->name));
172 json_object_object_add(object, "vendor",
173 json_object_new_int(device->wlr_device->vendor));
174 json_object_object_add(object, "product",
175 json_object_new_int(device->wlr_device->product));
176 json_object_object_add(object, "type",
177 json_object_new_string(describe_device_type(device)));
178
179 return object;
180}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index b7cd2d76..046e40a8 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -20,6 +20,7 @@
20#include "sway/ipc-json.h" 20#include "sway/ipc-json.h"
21#include "sway/ipc-server.h" 21#include "sway/ipc-server.h"
22#include "sway/server.h" 22#include "sway/server.h"
23#include "sway/input/input-manager.h"
23#include "list.h" 24#include "list.h"
24#include "log.h" 25#include "log.h"
25 26
@@ -359,6 +360,19 @@ void ipc_client_handle_command(struct ipc_client *client) {
359 goto exit_cleanup; 360 goto exit_cleanup;
360 } 361 }
361 362
363 case IPC_GET_INPUTS:
364 {
365 json_object *inputs = json_object_new_array();
366 struct sway_input_device *device = NULL;
367 wl_list_for_each(device, &input_manager->devices, link) {
368 json_object_array_add(inputs, ipc_json_describe_input(device));
369 }
370 const char *json_string = json_object_to_json_string(inputs);
371 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
372 json_object_put(inputs); // free
373 goto exit_cleanup;
374 }
375
362 case IPC_GET_TREE: 376 case IPC_GET_TREE:
363 { 377 {
364 json_object *tree = 378 json_object *tree =
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..fee2ddd2 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -2,13 +2,39 @@ 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/seat/fallback.c',
17 'commands/input/accel_profile.c',
18 'commands/input/click_method.c',
19 'commands/input/drag_lock.c',
20 'commands/input/dwt.c',
21 'commands/input/events.c',
22 'commands/input/left_handed.c',
23 'commands/input/middle_emulation.c',
24 'commands/input/natural_scroll.c',
25 'commands/input/pointer_accel.c',
26 'commands/input/scroll_method.c',
27 'commands/input/tap.c',
28 'commands/input/xkb_layout.c',
29 'commands/input/xkb_model.c',
30 'commands/input/xkb_options.c',
31 'commands/input/xkb_rules.c',
32 'commands/input/xkb_variant.c',
9 'commands/output.c', 33 'commands/output.c',
10 'config.c', 34 'config.c',
11 'config/output.c', 35 'config/output.c',
36 'config/seat.c',
37 'config/input.c',
12 'ipc-json.c', 38 'ipc-json.c',
13 'ipc-server.c', 39 'ipc-server.c',
14 'desktop/output.c', 40 'desktop/output.c',
@@ -28,6 +54,8 @@ sway_deps = [
28 wlroots, 54 wlroots,
29 libcap, 55 libcap,
30 math, 56 math,
57 libinput,
58 xkbcommon,
31] 59]
32 60
33executable( 61executable(
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/sway-input.5.txt b/sway/sway-input.5.txt
index f0c8f87c..0603616b 100644
--- a/sway/sway-input.5.txt
+++ b/sway/sway-input.5.txt
@@ -1,5 +1,5 @@
1///// 1/////
2vim:set ts=4 sw=4 tw=82 noet: 2vim:set ft=asciidoc ts=4 sw=4 tw=82 noet:
3///// 3/////
4sway-input (5) 4sway-input (5)
5============== 5==============
@@ -11,12 +11,37 @@ sway-input - input configuration file and commands
11Description 11Description
12----------- 12-----------
13 13
14Sway allows for configuration of libinput devices within the sway configuration file. 14Sway allows for configuration of devices within the sway configuration file.
15sway-input commands must be used inside an _input { }_ block in the config. 15sway-input commands must be used inside an _input { }_ block in the config.
16To obtain a list of available device identifiers, run **swaymsg -t get_inputs**. 16To obtain a list of available device identifiers, run **swaymsg -t get_inputs**.
17 17
18Commands 18Input Commands
19-------- 19--------------
20
21Keyboard Configuration
22~~~~~~~~~~~~~~~~~~~~~~
23
24For more information on these xkb configuration options, see
25**xkeyboard-config**(7).
26
27**input** <identifier> xkb_layout <layout_name>::
28 Sets the layout of the keyboard like _us_ or _de_.
29
30**input** <identifier> xkb_model <model_name>::
31 Sets the model of the keyboard. This has an influence for some extra keys your
32 keyboard might have.
33
34**input** <identifier> xkb_options <options>::
35 Sets extra xkb configuration options for the keyboard.
36
37**input** <identifier> xkb_rules <rules>::
38 Sets files of rules to be used for keyboard mapping composition.
39
40**input** <identifier> xkb_variant <variant>::
41 Sets the variant of the keyboard like _dvorak_ or _colemak_.
42
43Libinput Configuration
44~~~~~~~~~~~~~~~~~~~~~~
20 45
21**input** <identifier> accel_profile <adaptive|flat>:: 46**input** <identifier> accel_profile <adaptive|flat>::
22 Sets the pointer acceleration profile for the specified input device. 47 Sets the pointer acceleration profile for the specified input device.
@@ -53,6 +78,27 @@ Commands
53**input** <identifier> tap <enabled|disabled>:: 78**input** <identifier> tap <enabled|disabled>::
54 Enables or disables tap for specified input device. 79 Enables or disables tap for specified input device.
55 80
81Seat Configuration
82------------------
83
84Configure options for multiseat mode. sway-seat commands must be used inside a
85_seat { }_ block in the config.
86
87A _seat_ is a collection of input devices that act independently of each other.
88Seats are identified by name and the default seat is _seat0_ if no seats are
89configured. Each seat has an independent keyboard focus and a separate cursor that
90is controlled by the pointer devices of the seat. This is useful for multiple
91people using the desktop at the same time with their own devices (each sitting in
92their own "seat").
93
94**seat** <name> attach <input_identifier>::
95 Attach an input device to this seat by its input identifier. A special value
96 of _*_ will attach all devices to the seat.
97
98**seat** <name> fallback <true|false>::
99 Set this seat as the fallback seat. A fallback seat will attach any device not
100 explicitly attached to another seat (similar to a "default" seat).
101
56See Also 102See Also
57-------- 103--------
58 104
diff --git a/sway/sway.1.txt b/sway/sway.1.txt
index 14ab9f49..17fc13da 100644
--- a/sway/sway.1.txt
+++ b/sway/sway.1.txt
@@ -1,5 +1,5 @@
1///// 1/////
2vim:set ts=4 sw=4 tw=82 noet: 2vim:set ft=asciidoc ts=4 sw=4 tw=82 noet:
3///// 3/////
4:quotes.~: 4:quotes.~:
5 5
@@ -93,27 +93,6 @@ The following environment variables have an effect on sway:
93*SWAYSOCK*:: 93*SWAYSOCK*::
94 Specifies the path to the sway IPC socket. 94 Specifies the path to the sway IPC socket.
95 95
96*WLC_DRM_DEVICE*::
97 Specifies the device to use in DRM mode.
98
99*WLC_SHM*::
100 Set 1 to force EGL clients to use shared memory.
101
102*WLC_OUTPUTS*::
103 Number of fake outputs to use when running in X11 mode.
104
105*WLC_XWAYLAND*::
106 Set to 0 to disable Xwayland support.
107
108*WLC_LIBINPUT*::
109 Set to 1 to force libinput (even in X11 mode).
110
111*WLC_REPEAT_DELAY*::
112 Configures the keyboard repeat delay.
113
114*WLC_REPEAT_RATE*::
115 Configures the keyboard repeat rate.
116
117*XKB_DEFAULT_RULES*, *XKB_DEFAULT_MODEL*, *XKB_DEFAULT_LAYOUT*, *XKB_DEFAULT_VARIANT*, *XKB_DEFAULT_OPTIONS*:: 96*XKB_DEFAULT_RULES*, *XKB_DEFAULT_MODEL*, *XKB_DEFAULT_LAYOUT*, *XKB_DEFAULT_VARIANT*, *XKB_DEFAULT_OPTIONS*::
118 Configures the xkb keyboard settings. See xkeyboard-config(7). 97 Configures the xkb keyboard settings. See xkeyboard-config(7).
119 98
diff --git a/sway/sway.5.txt b/sway/sway.5.txt
index 2a4ef205..afd3c9fa 100644
--- a/sway/sway.5.txt
+++ b/sway/sway.5.txt
@@ -312,7 +312,7 @@ The default colors are:
312**hide_edge_borders** <none|vertical|horizontal|both|smart>:: 312**hide_edge_borders** <none|vertical|horizontal|both|smart>::
313 Hide window borders adjacent to the screen edges. Default is _none_. 313 Hide window borders adjacent to the screen edges. Default is _none_.
314 314
315**input** <input device> <block of commands>:: 315**input** <input_device> <block of commands>::
316 Append _{_ to this command, the following lines will be commands to configure 316 Append _{_ to this command, the following lines will be commands to configure
317 the named input device, and _}_ on its own line will close the block. 317 the named input device, and _}_ on its own line will close the block.
318 + 318 +
@@ -320,6 +320,11 @@ The default colors are:
320 + 320 +
321 See **sway-input**(5) for details. 321 See **sway-input**(5) for details.
322 322
323**seat** <seat_name> <block of commands>::
324 Append _{_ to this command, the following lines will be commands to configure
325 the named seat, and _}_ on its own line will close the block.
326 See **sway-input**(5) for details.
327
323**kill**:: 328**kill**::
324 Kills (force-closes) the currently-focused container and all of its children. 329 Kills (force-closes) the currently-focused container and all of its children.
325 330
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}
diff --git a/swaymsg/main.c b/swaymsg/main.c
index 2f9cfb14..b431872a 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -61,55 +61,49 @@ static void pretty_print_workspace(json_object *w) {
61 ); 61 );
62} 62}
63 63
64static void pretty_print_input(json_object *i) { 64static const char *pretty_type_name(const char *name) {
65 json_object *id, *name, *size, *caps; 65 // TODO these constants probably belong in the common lib
66 json_object_object_get_ex(i, "identifier", &id);
67 json_object_object_get_ex(i, "name", &name);
68 json_object_object_get_ex(i, "size", &size);
69 json_object_object_get_ex(i, "capabilities", &caps);
70
71 printf( "Input device %s\n Type: ", json_object_get_string(name));
72
73 struct { 66 struct {
74 const char *a; 67 const char *a;
75 const char *b; 68 const char *b;
76 } cap_names[] = { 69 } type_names[] = {
77 { "keyboard", "Keyboard" }, 70 { "keyboard", "Keyboard" },
78 { "pointer", "Mouse" }, 71 { "pointer", "Mouse" },
79 { "touch", "Touch" },
80 { "tablet_tool", "Tablet tool" },
81 { "tablet_pad", "Tablet pad" }, 72 { "tablet_pad", "Tablet pad" },
82 { "gesture", "Gesture" }, 73 { "tablet_tool", "Tablet tool" },
83 { "switch", "Switch" }, 74 { "touch", "Touch" },
84 }; 75 };
85 76
86 size_t len = json_object_array_length(caps); 77 for (size_t i = 0; i < sizeof(type_names) / sizeof(type_names[0]); ++i) {
87 if (len == 0) { 78 if (strcmp(type_names[i].a, name) == 0) {
88 printf("Unknown"); 79 return type_names[i].b;
89 }
90
91 json_object *cap;
92 for (size_t i = 0; i < len; ++i) {
93 cap = json_object_array_get_idx(caps, i);
94 const char *cap_s = json_object_get_string(cap);
95 const char *_name = NULL;
96 for (size_t j = 0; j < sizeof(cap_names) / sizeof(cap_names[0]); ++i) {
97 if (strcmp(cap_names[i].a, cap_s) == 0) {
98 _name = cap_names[i].b;
99 break;
100 }
101 } 80 }
102 printf("%s%s", _name ? _name : cap_s, len > 1 && i != len - 1 ? ", " : "");
103 }
104 printf("\n Sway ID: %s\n", json_object_get_string(id));
105 if (size) {
106 json_object *width, *height;
107 json_object_object_get_ex(size, "width", &width);
108 json_object_object_get_ex(size, "height", &height);
109 printf(" Size: %lfmm x %lfmm\n",
110 json_object_get_double(width), json_object_get_double(height));
111 } 81 }
112 printf("\n"); 82
83 return name;
84}
85
86static void pretty_print_input(json_object *i) {
87 json_object *id, *name, *type, *product, *vendor;
88 json_object_object_get_ex(i, "identifier", &id);
89 json_object_object_get_ex(i, "name", &name);
90 json_object_object_get_ex(i, "type", &type);
91 json_object_object_get_ex(i, "product", &product);
92 json_object_object_get_ex(i, "vendor", &vendor);
93
94 const char *fmt =
95 "Input device: %s\n"
96 " Type: %s\n"
97 " Identifier: %s\n"
98 " Product ID: %d\n"
99 " Vendor ID: %d\n\n";
100
101
102 printf(fmt, json_object_get_string(name),
103 pretty_type_name(json_object_get_string(type)),
104 json_object_get_string(id),
105 json_object_get_int(product),
106 json_object_get_int(vendor));
113} 107}
114 108
115static void pretty_print_output(json_object *o) { 109static void pretty_print_output(json_object *o) {
@@ -314,9 +308,11 @@ int main(int argc, char **argv) {
314 } 308 }
315 free(cmdtype); 309 free(cmdtype);
316 310
317 char *command = strdup(""); 311 char *command = NULL;
318 if (optind < argc) { 312 if (optind < argc) {
319 command = join_args(argv + optind, argc - optind); 313 command = join_args(argv + optind, argc - optind);
314 } else {
315 command = strdup("");
320 } 316 }
321 317
322 int ret = 0; 318 int ret = 0;
@@ -341,7 +337,7 @@ int main(int argc, char **argv) {
341 } else { 337 } else {
342 pretty_print(type, obj); 338 pretty_print(type, obj);
343 } 339 }
344 free(obj); 340 json_object_put(obj);
345 } 341 }
346 } 342 }
347 close(socketfd); 343 close(socketfd);