summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/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.c132
-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.c184
-rw-r--r--sway/input/input-manager.c304
-rw-r--r--sway/input/input.c77
-rw-r--r--sway/input/keyboard.c114
-rw-r--r--sway/input/seat.c252
-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.txt50
-rw-r--r--sway/sway.1.txt23
-rw-r--r--sway/sway.5.txt7
-rw-r--r--sway/tree/container.c67
49 files changed, 2231 insertions, 158 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/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..dac028a7
--- /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 (argc > 2) {
20 int argc_new = argc-2;
21 char **argv_new = argv+2;
22
23 struct cmd_results *res;
24 current_input_config = new_input_config(argv[0]);
25 if (strcasecmp("accel_profile", argv[1]) == 0) {
26 res = input_cmd_accel_profile(argc_new, argv_new);
27 } else if (strcasecmp("click_method", argv[1]) == 0) {
28 res = input_cmd_click_method(argc_new, argv_new);
29 } else if (strcasecmp("drag_lock", argv[1]) == 0) {
30 res = input_cmd_drag_lock(argc_new, argv_new);
31 } else if (strcasecmp("dwt", argv[1]) == 0) {
32 res = input_cmd_dwt(argc_new, argv_new);
33 } else if (strcasecmp("events", argv[1]) == 0) {
34 res = input_cmd_events(argc_new, argv_new);
35 } else if (strcasecmp("left_handed", argv[1]) == 0) {
36 res = input_cmd_left_handed(argc_new, argv_new);
37 } else if (strcasecmp("middle_emulation", argv[1]) == 0) {
38 res = input_cmd_middle_emulation(argc_new, argv_new);
39 } else if (strcasecmp("natural_scroll", argv[1]) == 0) {
40 res = input_cmd_natural_scroll(argc_new, argv_new);
41 } else if (strcasecmp("pointer_accel", argv[1]) == 0) {
42 res = input_cmd_pointer_accel(argc_new, argv_new);
43 } else if (strcasecmp("scroll_method", argv[1]) == 0) {
44 res = input_cmd_scroll_method(argc_new, argv_new);
45 } else if (strcasecmp("tap", argv[1]) == 0) {
46 res = input_cmd_tap(argc_new, argv_new);
47 } else if (strcasecmp("xkb_layout", argv[1]) == 0) {
48 res = input_cmd_xkb_layout(argc_new, argv_new);
49 } else if (strcasecmp("xkb_model", argv[1]) == 0) {
50 res = input_cmd_xkb_model(argc_new, argv_new);
51 } else if (strcasecmp("xkb_options", argv[1]) == 0) {
52 res = input_cmd_xkb_options(argc_new, argv_new);
53 } else if (strcasecmp("xkb_rules", argv[1]) == 0) {
54 res = input_cmd_xkb_rules(argc_new, argv_new);
55 } else if (strcasecmp("xkb_variant", argv[1]) == 0) {
56 res = input_cmd_xkb_variant(argc_new, argv_new);
57 } else {
58 res = cmd_results_new(CMD_INVALID, "input <device>", "Unknown command %s", argv[1]);
59 }
60 current_input_config = NULL;
61 return res;
62 }
63
64 return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL);
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..0149762a
--- /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 (argc > 2) {
20 int argc_new = argc-2;
21 char **argv_new = argv+2;
22
23 struct cmd_results *res;
24 current_seat_config = new_seat_config(argv[0]);
25 if (strcasecmp("attach", argv[1]) == 0) {
26 res = seat_cmd_attach(argc_new, argv_new);
27 } else if (strcasecmp("fallback", argv[1]) == 0) {
28 res = seat_cmd_fallback(argc_new, argv_new);
29 } else {
30 res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]);
31 }
32 current_seat_config = NULL;
33 return res;
34 }
35
36 return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL);
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..4c9e8d0d
--- /dev/null
+++ b/sway/config/seat.c
@@ -0,0 +1,132 @@
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 return NULL;
18 }
19
20 seat->fallback = -1;
21 seat->attachments = create_list();
22 if (!sway_assert(seat->attachments,
23 "could not allocate seat attachments list")) {
24 return NULL;
25 }
26
27 return seat;
28}
29
30struct seat_attachment_config *seat_attachment_config_new() {
31 struct seat_attachment_config *attachment =
32 calloc(1, sizeof(struct seat_attachment_config));
33 if (!attachment) {
34 sway_log(L_DEBUG, "cannot allocate attachment config");
35 return NULL;
36 }
37 return attachment;
38}
39
40static void seat_attachment_config_free(
41 struct seat_attachment_config *attachment) {
42 free(attachment->identifier);
43 free(attachment);
44 return;
45}
46
47static struct seat_attachment_config *seat_attachment_config_copy(
48 struct seat_attachment_config *attachment) {
49 struct seat_attachment_config *copy = seat_attachment_config_new();
50 if (!copy) {
51 return NULL;
52 }
53
54 copy->identifier = strdup(attachment->identifier);
55
56 return copy;
57}
58
59static void merge_seat_attachment_config(struct seat_attachment_config *dest,
60 struct seat_attachment_config *source) {
61 // nothing to merge yet, but there will be some day
62}
63
64void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
65 if (source->name) {
66 free(dest->name);
67 dest->name = strdup(source->name);
68 }
69
70 if (source->fallback != -1) {
71 dest->fallback = source->fallback;
72 }
73
74 for (int i = 0; i < source->attachments->length; ++i) {
75 struct seat_attachment_config *source_attachment =
76 source->attachments->items[i];
77 bool found = false;
78 for (int j = 0; j < dest->attachments->length; ++j) {
79 struct seat_attachment_config *dest_attachment =
80 dest->attachments->items[j];
81 if (strcmp(source_attachment->identifier,
82 dest_attachment->identifier) == 0) {
83 merge_seat_attachment_config(dest_attachment,
84 source_attachment);
85 found = true;
86 }
87 }
88
89 if (!found) {
90 struct seat_attachment_config *copy =
91 seat_attachment_config_copy(source_attachment);
92 if (copy) {
93 list_add(dest->attachments, copy);
94 }
95 }
96 }
97}
98
99void free_seat_config(struct seat_config *seat) {
100 if (!seat) {
101 return;
102 }
103
104 free(seat->name);
105 for (int i = 0; i < seat->attachments->length; ++i) {
106 struct seat_attachment_config *attachment =
107 seat->attachments->items[i];
108 seat_attachment_config_free(attachment);
109 }
110
111 list_free(seat->attachments);
112 free(seat);
113}
114
115int seat_name_cmp(const void *item, const void *data) {
116 const struct seat_config *sc = item;
117 const char *name = data;
118 return strcmp(sc->name, name);
119}
120
121struct seat_attachment_config *seat_config_get_attachment(
122 struct seat_config *seat_config, char *identifier) {
123 for (int i = 0; i < seat_config->attachments->length; ++i) {
124 struct seat_attachment_config *attachment =
125 seat_config->attachments->items[i];
126 if (strcmp(attachment->identifier, identifier) == 0) {
127 return attachment;
128 }
129 }
130
131 return NULL;
132}
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..24d4642d
--- /dev/null
+++ b/sway/input/cursor.c
@@ -0,0 +1,184 @@
1#define _XOPEN_SOURCE 700
2#ifdef __linux__
3#include <linux/input-event-codes.h>
4#elif __FreeBSD__
5#include <dev/evdev/input-event-codes.h>
6#endif
7#include <wlr/types/wlr_cursor.h>
8#include <wlr/types/wlr_xcursor_manager.h>
9#include "sway/input/cursor.h"
10#include "sway/view.h"
11#include "list.h"
12#include "log.h"
13
14static void cursor_update_position(struct sway_cursor *cursor) {
15 double x = cursor->cursor->x;
16 double y = cursor->cursor->y;
17
18 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
19 "left_ptr", cursor->cursor);
20
21 cursor->x = x;
22 cursor->y = y;
23}
24
25static void cursor_send_pointer_motion(struct sway_cursor *cursor,
26 uint32_t time) {
27 struct wlr_seat *seat = cursor->seat->wlr_seat;
28 struct wlr_surface *surface = NULL;
29 double sx, sy;
30 swayc_t *swayc =
31 swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy);
32 if (swayc) {
33 wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
34 wlr_seat_pointer_notify_motion(seat, time, sx, sy);
35 } else {
36 wlr_seat_pointer_clear_focus(seat);
37 }
38}
39
40static void handle_cursor_motion(struct wl_listener *listener, void *data) {
41 struct sway_cursor *cursor =
42 wl_container_of(listener, cursor, motion);
43 struct wlr_event_pointer_motion *event = data;
44 wlr_cursor_move(cursor->cursor, event->device,
45 event->delta_x, event->delta_y);
46 cursor_update_position(cursor);
47 cursor_send_pointer_motion(cursor, event->time_msec);
48}
49
50static void handle_cursor_motion_absolute(struct wl_listener *listener,
51 void *data) {
52 struct sway_cursor *cursor =
53 wl_container_of(listener, cursor, motion_absolute);
54 struct wlr_event_pointer_motion_absolute *event = data;
55 wlr_cursor_warp_absolute(cursor->cursor, event->device,
56 event->x_mm / event->width_mm, event->y_mm / event->height_mm);
57 cursor_update_position(cursor);
58 cursor_send_pointer_motion(cursor, event->time_msec);
59}
60
61static void handle_cursor_button(struct wl_listener *listener, void *data) {
62 struct sway_cursor *cursor =
63 wl_container_of(listener, cursor, button);
64 struct wlr_event_pointer_button *event = data;
65
66 if (event->button == BTN_LEFT) {
67 struct wlr_surface *surface = NULL;
68 double sx, sy;
69 swayc_t *swayc =
70 swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy);
71
72 sway_seat_set_focus(cursor->seat, swayc);
73 }
74
75 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec,
76 event->button, event->state);
77}
78
79static void handle_cursor_axis(struct wl_listener *listener, void *data) {
80 struct sway_cursor *cursor =
81 wl_container_of(listener, cursor, axis);
82 struct wlr_event_pointer_axis *event = data;
83 wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
84 event->orientation, event->delta);
85}
86
87static void handle_touch_down(struct wl_listener *listener, void *data) {
88 struct sway_cursor *cursor =
89 wl_container_of(listener, cursor, touch_down);
90 struct wlr_event_touch_down *event = data;
91 sway_log(L_DEBUG, "TODO: handle touch down event: %p", event);
92}
93
94static void handle_touch_up(struct wl_listener *listener, void *data) {
95 struct sway_cursor *cursor =
96 wl_container_of(listener, cursor, touch_up);
97 struct wlr_event_touch_up *event = data;
98 sway_log(L_DEBUG, "TODO: handle touch up event: %p", event);
99}
100
101static void handle_touch_motion(struct wl_listener *listener, void *data) {
102 struct sway_cursor *cursor =
103 wl_container_of(listener, cursor, touch_motion);
104 struct wlr_event_touch_motion *event = data;
105 sway_log(L_DEBUG, "TODO: handle touch motion event: %p", event);
106}
107
108static void handle_tool_axis(struct wl_listener *listener, void *data) {
109 struct sway_cursor *cursor =
110 wl_container_of(listener, cursor, tool_axis);
111 struct wlr_event_tablet_tool_axis *event = data;
112 sway_log(L_DEBUG, "TODO: handle tool axis event: %p", event);
113}
114
115static void handle_tool_tip(struct wl_listener *listener, void *data) {
116 struct sway_cursor *cursor =
117 wl_container_of(listener, cursor, tool_tip);
118 struct wlr_event_tablet_tool_tip *event = data;
119 sway_log(L_DEBUG, "TODO: handle tool tip event: %p", event);
120}
121
122static void handle_request_set_cursor(struct wl_listener *listener,
123 void *data) {
124 struct sway_cursor *cursor =
125 wl_container_of(listener, cursor, request_set_cursor);
126 struct wlr_seat_pointer_request_set_cursor_event *event = data;
127 sway_log(L_DEBUG, "TODO: handle request set cursor event: %p", event);
128}
129
130struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
131 struct sway_cursor *cursor = calloc(1, sizeof(struct sway_cursor));
132 if (!sway_assert(cursor, "could not allocate sway cursor")) {
133 return NULL;
134 }
135
136 struct wlr_cursor *wlr_cursor = wlr_cursor_create();
137 if (!sway_assert(wlr_cursor, "could not allocate wlr cursor")) {
138 free(cursor);
139 return NULL;
140 }
141
142 cursor->seat = seat;
143 wlr_cursor_attach_output_layout(wlr_cursor,
144 root_container.sway_root->output_layout);
145
146 // input events
147 wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
148 cursor->motion.notify = handle_cursor_motion;
149
150 wl_signal_add(&wlr_cursor->events.motion_absolute,
151 &cursor->motion_absolute);
152 cursor->motion_absolute.notify = handle_cursor_motion_absolute;
153
154 wl_signal_add(&wlr_cursor->events.button, &cursor->button);
155 cursor->button.notify = handle_cursor_button;
156
157 wl_signal_add(&wlr_cursor->events.axis, &cursor->axis);
158 cursor->axis.notify = handle_cursor_axis;
159
160 wl_signal_add(&wlr_cursor->events.touch_down, &cursor->touch_down);
161 cursor->touch_down.notify = handle_touch_down;
162
163 wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up);
164 cursor->touch_up.notify = handle_touch_up;
165
166 wl_signal_add(&wlr_cursor->events.touch_motion,
167 &cursor->touch_motion);
168 cursor->touch_motion.notify = handle_touch_motion;
169
170 wl_signal_add(&wlr_cursor->events.tablet_tool_axis,
171 &cursor->tool_axis);
172 cursor->tool_axis.notify = handle_tool_axis;
173
174 wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip);
175 cursor->tool_tip.notify = handle_tool_tip;
176
177 wl_signal_add(&seat->wlr_seat->events.request_set_cursor,
178 &cursor->request_set_cursor);
179 cursor->request_set_cursor.notify = handle_request_set_cursor;
180
181 cursor->cursor = wlr_cursor;
182
183 return cursor;
184}
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
new file mode 100644
index 00000000..52da8f5e
--- /dev/null
+++ b/sway/input/input-manager.c
@@ -0,0 +1,304 @@
1#define _XOPEN_SOURCE 700
2#include <ctype.h>
3#include <float.h>
4#include <limits.h>
5#include <stdio.h>
6#include <string.h>
7#include <libinput.h>
8#include <math.h>
9#include "sway/config.h"
10#include "sway/input/input-manager.h"
11#include "sway/input/seat.h"
12#include "sway/server.h"
13#include "stringop.h"
14#include "list.h"
15#include "log.h"
16
17static const char *default_seat = "seat0";
18
19// TODO make me not global
20struct sway_input_manager *input_manager;
21
22struct input_config *current_input_config = NULL;
23struct seat_config *current_seat_config = NULL;
24
25static struct sway_seat *input_manager_get_seat(
26 struct sway_input_manager *input, const char *seat_name) {
27 struct sway_seat *seat = NULL;
28 wl_list_for_each(seat, &input->seats, link) {
29 if (strcmp(seat->wlr_seat->name, seat_name) == 0) {
30 return seat;
31 }
32 }
33
34 return sway_seat_create(input, seat_name);
35}
36
37static inline int strlen_num(int num) {
38 if (num == 0) {
39 return 2;
40 }
41 return (int)((ceil(log10(abs(num)))+2));
42}
43
44static char *get_device_identifier(struct wlr_input_device *device) {
45 int vendor = device->vendor;
46 int product = device->product;
47 char *name = strdup(device->name);
48 name = strip_whitespace(name);
49
50 char *p = name;
51 for (; *p; ++p) {
52 if (*p == ' ') {
53 *p = '_';
54 }
55 }
56
57 int len =
58 (strlen(name) +
59 strlen_num(device->vendor) +
60 strlen_num(device->product) +
61 3) * sizeof(char);
62
63 char *identifier = malloc(len);
64 if (!identifier) {
65 sway_log(L_ERROR, "Unable to allocate unique input device name");
66 return NULL;
67 }
68
69 const char *fmt = "%d:%d:%s";
70 snprintf(identifier, len, fmt, vendor, product, name);
71 free(name);
72 return identifier;
73}
74
75static struct sway_input_device *input_sway_device_from_wlr(
76 struct sway_input_manager *input, struct wlr_input_device *device) {
77 struct sway_input_device *input_device = NULL;
78 wl_list_for_each(input_device, &input->devices, link) {
79 if (input_device->wlr_device == device) {
80 return input_device;
81 }
82 }
83 return NULL;
84}
85
86static bool input_has_seat_configuration(struct sway_input_manager *input) {
87 struct sway_seat *seat = NULL;
88 wl_list_for_each(seat, &input->seats, link) {
89 if (seat->config) {
90 return true;
91 }
92 }
93
94 return false;
95}
96
97static void input_add_notify(struct wl_listener *listener, void *data) {
98 struct sway_input_manager *input =
99 wl_container_of(listener, input, input_add);
100 struct wlr_input_device *device = data;
101
102 struct sway_input_device *input_device =
103 calloc(1, sizeof(struct sway_input_device));
104 if (!sway_assert(input_device, "could not allocate input device")) {
105 return;
106 }
107
108 input_device->wlr_device = device;
109 input_device->identifier = get_device_identifier(device);
110 wl_list_insert(&input->devices, &input_device->link);
111
112 sway_log(L_DEBUG, "adding device: '%s'",
113 input_device->identifier);
114
115 // find config
116 for (int i = 0; i < config->input_configs->length; ++i) {
117 struct input_config *input_config = config->input_configs->items[i];
118 if (strcmp(input_config->identifier, input_device->identifier) == 0) {
119 input_device->config = input_config;
120 break;
121 }
122 }
123
124 struct sway_seat *seat = NULL;
125 if (!input_has_seat_configuration(input)) {
126 sway_log(L_DEBUG, "no seat configuration, using default seat");
127 seat = input_manager_get_seat(input, default_seat);
128 sway_seat_add_device(seat, input_device);
129 return;
130 }
131
132 bool added = false;
133 wl_list_for_each(seat, &input->seats, link) {
134 if (seat->config &&
135 (seat_config_get_attachment(seat->config,
136 input_device->identifier) ||
137 seat_config_get_attachment(seat->config, "*"))) {
138 sway_seat_add_device(seat, input_device);
139 added = true;
140 }
141 }
142
143 if (!added) {
144 wl_list_for_each(seat, &input->seats, link) {
145 if (seat->config && seat->config->fallback == 1) {
146 sway_seat_add_device(seat, input_device);
147 added = true;
148 }
149 }
150 }
151
152 if (!added) {
153 sway_log(L_DEBUG,
154 "device '%s' is not configured on any seats",
155 input_device->identifier);
156 }
157}
158
159static void input_remove_notify(struct wl_listener *listener, void *data) {
160 struct sway_input_manager *input =
161 wl_container_of(listener, input, input_remove);
162 struct wlr_input_device *device = data;
163
164 struct sway_input_device *input_device =
165 input_sway_device_from_wlr(input, device);
166
167 if (!sway_assert(input_device, "could not find sway device")) {
168 return;
169 }
170
171 sway_log(L_DEBUG, "removing device: '%s'",
172 input_device->identifier);
173
174 struct sway_seat *seat = NULL;
175 wl_list_for_each(seat, &input->seats, link) {
176 sway_seat_remove_device(seat, input_device);
177 }
178
179 wl_list_remove(&input_device->link);
180 free(input_device->identifier);
181 free(input_device);
182}
183
184struct sway_input_manager *sway_input_manager_create(
185 struct sway_server *server) {
186 struct sway_input_manager *input =
187 calloc(1, sizeof(struct sway_input_manager));
188 if (!input) {
189 return NULL;
190 }
191 input->server = server;
192
193 wl_list_init(&input->devices);
194 wl_list_init(&input->seats);
195
196 // create the default seat
197 input_manager_get_seat(input, default_seat);
198
199 input->input_add.notify = input_add_notify;
200 wl_signal_add(&server->backend->events.input_add, &input->input_add);
201
202 input->input_remove.notify = input_remove_notify;
203 wl_signal_add(&server->backend->events.input_remove, &input->input_remove);
204
205 return input;
206}
207
208bool sway_input_manager_has_focus(struct sway_input_manager *input,
209 swayc_t *container) {
210 struct sway_seat *seat = NULL;
211 wl_list_for_each(seat, &input->seats, link) {
212 if (seat->focus == container) {
213 return true;
214 }
215 }
216
217 return false;
218}
219
220void sway_input_manager_set_focus(struct sway_input_manager *input,
221 swayc_t *container) {
222 struct sway_seat *seat ;
223 wl_list_for_each(seat, &input->seats, link) {
224 sway_seat_set_focus(seat, container);
225 }
226}
227
228void sway_input_manager_apply_input_config(struct sway_input_manager *input,
229 struct input_config *input_config) {
230 struct sway_input_device *input_device = NULL;
231 wl_list_for_each(input_device, &input->devices, link) {
232 if (strcmp(input_device->identifier, input_config->identifier) == 0) {
233 input_device->config = input_config;
234
235 struct sway_seat *seat = NULL;
236 wl_list_for_each(seat, &input->seats, link) {
237 sway_seat_configure_device(seat, input_device);
238 }
239 }
240 }
241}
242
243void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
244 struct seat_config *seat_config) {
245 sway_log(L_DEBUG, "applying new seat config for seat %s",
246 seat_config->name);
247 struct sway_seat *seat = input_manager_get_seat(input, seat_config->name);
248 if (!seat) {
249 return;
250 }
251
252 sway_seat_set_config(seat, seat_config);
253
254 // for every device, try to add it to a seat and if no seat has it
255 // attached, add it to the fallback seats.
256 struct sway_input_device *input_device = NULL;
257 wl_list_for_each(input_device, &input->devices, link) {
258 list_t *seat_list = create_list();
259 struct sway_seat *seat = NULL;
260 wl_list_for_each(seat, &input->seats, link) {
261 if (!seat->config) {
262 continue;
263 }
264 if (seat_config_get_attachment(seat->config, "*") ||
265 seat_config_get_attachment(seat->config,
266 input_device->identifier)) {
267 list_add(seat_list, seat);
268 }
269 }
270
271 if (seat_list->length) {
272 wl_list_for_each(seat, &input->seats, link) {
273 bool attached = false;
274 for (int i = 0; i < seat_list->length; ++i) {
275 if (seat == seat_list->items[i]) {
276 attached = true;
277 break;
278 }
279 }
280 if (attached) {
281 sway_seat_add_device(seat, input_device);
282 } else {
283 sway_seat_remove_device(seat, input_device);
284 }
285 }
286 } else {
287 wl_list_for_each(seat, &input->seats, link) {
288 if (seat->config && seat->config->fallback == 1) {
289 sway_seat_add_device(seat, input_device);
290 } else {
291 sway_seat_remove_device(seat, input_device);
292 }
293 }
294 }
295 list_free(seat_list);
296 }
297}
298
299void sway_input_manager_configure_xcursor(struct sway_input_manager *input) {
300 struct sway_seat *seat = NULL;
301 wl_list_for_each(seat, &input->seats, link) {
302 sway_seat_configure_xcursor(seat);
303 }
304}
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..bb18edd2
--- /dev/null
+++ b/sway/input/keyboard.c
@@ -0,0 +1,114 @@
1#include "sway/input/seat.h"
2#include "sway/input/keyboard.h"
3#include "sway/input/input-manager.h"
4#include "log.h"
5
6static void handle_keyboard_key(struct wl_listener *listener, void *data) {
7 struct sway_keyboard *keyboard =
8 wl_container_of(listener, keyboard, keyboard_key);
9 struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
10 struct wlr_input_device *wlr_device =
11 keyboard->seat_device->input_device->wlr_device;
12 struct wlr_event_keyboard_key *event = data;
13 wlr_seat_set_keyboard(wlr_seat, wlr_device);
14 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
15 event->keycode, event->state);
16}
17
18static void handle_keyboard_modifiers(struct wl_listener *listener,
19 void *data) {
20 struct sway_keyboard *keyboard =
21 wl_container_of(listener, keyboard, keyboard_modifiers);
22 struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
23 struct wlr_input_device *wlr_device =
24 keyboard->seat_device->input_device->wlr_device;
25 wlr_seat_set_keyboard(wlr_seat, wlr_device);
26 wlr_seat_keyboard_notify_modifiers(wlr_seat);
27}
28
29struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
30 struct sway_seat_device *device) {
31 struct sway_keyboard *keyboard =
32 calloc(1, sizeof(struct sway_keyboard));
33 if (!sway_assert(keyboard, "could not allocate sway keyboard")) {
34 return NULL;
35 }
36
37 keyboard->seat_device = device;
38 device->keyboard = keyboard;
39
40 wl_list_init(&keyboard->keyboard_key.link);
41 wl_list_init(&keyboard->keyboard_modifiers.link);
42
43 return keyboard;
44}
45
46void sway_keyboard_configure(struct sway_keyboard *keyboard) {
47 struct xkb_rule_names rules;
48 memset(&rules, 0, sizeof(rules));
49 struct input_config *input_config =
50 keyboard->seat_device->input_device->config;
51 struct wlr_input_device *wlr_device =
52 keyboard->seat_device->input_device->wlr_device;
53
54 if (input_config && input_config->xkb_layout) {
55 rules.layout = input_config->xkb_layout;
56 } else {
57 rules.layout = getenv("XKB_DEFAULT_LAYOUT");
58 }
59 if (input_config && input_config->xkb_model) {
60 rules.model = input_config->xkb_model;
61 } else {
62 rules.model = getenv("XKB_DEFAULT_MODEL");
63 }
64
65 if (input_config && input_config->xkb_options) {
66 rules.options = input_config->xkb_options;
67 } else {
68 rules.options = getenv("XKB_DEFAULT_OPTIONS");
69 }
70
71 if (input_config && input_config->xkb_rules) {
72 rules.rules = input_config->xkb_rules;
73 } else {
74 rules.rules = getenv("XKB_DEFAULT_RULES");
75 }
76
77 if (input_config && input_config->xkb_variant) {
78 rules.variant = input_config->xkb_variant;
79 } else {
80 rules.variant = getenv("XKB_DEFAULT_VARIANT");
81 }
82
83 struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
84 if (!sway_assert(context, "cannot create XKB context")) {
85 return;
86 }
87
88 xkb_keymap_unref(keyboard->keymap);
89 keyboard->keymap =
90 xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
91 wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap);
92 wlr_keyboard_set_repeat_info(wlr_device->keyboard, 25, 600);
93 xkb_context_unref(context);
94 struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
95 wlr_seat_set_keyboard(seat, wlr_device);
96
97 wl_list_remove(&keyboard->keyboard_key.link);
98 wl_signal_add(&wlr_device->keyboard->events.key, &keyboard->keyboard_key);
99 keyboard->keyboard_key.notify = handle_keyboard_key;
100
101 wl_list_remove(&keyboard->keyboard_modifiers.link);
102 wl_signal_add( &wlr_device->keyboard->events.modifiers,
103 &keyboard->keyboard_modifiers);
104 keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
105}
106
107void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
108 if (!keyboard) {
109 return;
110 }
111 wl_list_remove(&keyboard->keyboard_key.link);
112 wl_list_remove(&keyboard->keyboard_modifiers.link);
113 free(keyboard);
114}
diff --git a/sway/input/seat.c b/sway/input/seat.c
new file mode 100644
index 00000000..df1427fa
--- /dev/null
+++ b/sway/input/seat.c
@@ -0,0 +1,252 @@
1#define _XOPEN_SOURCE 700
2#include <wlr/types/wlr_cursor.h>
3#include <wlr/types/wlr_xcursor_manager.h>
4#include "sway/input/seat.h"
5#include "sway/input/cursor.h"
6#include "sway/input/input-manager.h"
7#include "sway/input/keyboard.h"
8#include "sway/output.h"
9#include "sway/view.h"
10#include "log.h"
11
12static void seat_device_destroy(struct sway_seat_device *seat_device) {
13 if (!seat_device) {
14 return;
15 }
16
17 sway_keyboard_destroy(seat_device->keyboard);
18 wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor,
19 seat_device->input_device->wlr_device);
20 wl_list_remove(&seat_device->link);
21 free(seat_device);
22}
23
24struct sway_seat *sway_seat_create(struct sway_input_manager *input,
25 const char *seat_name) {
26 struct sway_seat *seat = calloc(1, sizeof(struct sway_seat));
27 if (!seat) {
28 return NULL;
29 }
30
31 seat->wlr_seat = wlr_seat_create(input->server->wl_display, seat_name);
32 if (!sway_assert(seat->wlr_seat, "could not allocate seat")) {
33 return NULL;
34 }
35
36 seat->cursor = sway_cursor_create(seat);
37 if (!seat->cursor) {
38 wlr_seat_destroy(seat->wlr_seat);
39 free(seat);
40 return NULL;
41 }
42
43 seat->input = input;
44 wl_list_init(&seat->devices);
45
46 wlr_seat_set_capabilities(seat->wlr_seat,
47 WL_SEAT_CAPABILITY_KEYBOARD |
48 WL_SEAT_CAPABILITY_POINTER |
49 WL_SEAT_CAPABILITY_TOUCH);
50
51 sway_seat_configure_xcursor(seat);
52
53 wl_list_insert(&input->seats, &seat->link);
54
55 return seat;
56}
57
58static void seat_configure_pointer(struct sway_seat *seat,
59 struct sway_seat_device *sway_device) {
60 // TODO pointer configuration
61 wlr_cursor_attach_input_device(seat->cursor->cursor,
62 sway_device->input_device->wlr_device);
63}
64
65static void seat_configure_keyboard(struct sway_seat *seat,
66 struct sway_seat_device *seat_device) {
67 if (!seat_device->keyboard) {
68 sway_keyboard_create(seat, seat_device);
69 }
70 sway_keyboard_configure(seat_device->keyboard);
71 wlr_seat_set_keyboard(seat->wlr_seat,
72 seat_device->input_device->wlr_device);
73 if (seat->focus) {
74 // force notify reenter to pick up the new configuration
75 wlr_seat_keyboard_clear_focus(seat->wlr_seat);
76 wlr_seat_keyboard_notify_enter(seat->wlr_seat, seat->focus->sway_view->surface);
77 }
78}
79
80static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat,
81 struct sway_input_device *input_device) {
82 struct sway_seat_device *seat_device = NULL;
83 wl_list_for_each(seat_device, &seat->devices, link) {
84 if (seat_device->input_device == input_device) {
85 return seat_device;
86 }
87 }
88
89 return NULL;
90}
91
92void sway_seat_configure_device(struct sway_seat *seat,
93 struct sway_input_device *input_device) {
94 struct sway_seat_device *seat_device =
95 sway_seat_get_device(seat, input_device);
96 if (!seat_device) {
97 return;
98 }
99
100 if (seat->config) {
101 seat_device->attachment_config =
102 seat_config_get_attachment(seat->config, input_device->identifier);
103 }
104
105 switch (input_device->wlr_device->type) {
106 case WLR_INPUT_DEVICE_POINTER:
107 seat_configure_pointer(seat, seat_device);
108 break;
109 case WLR_INPUT_DEVICE_KEYBOARD:
110 seat_configure_keyboard(seat, seat_device);
111 break;
112 case WLR_INPUT_DEVICE_TOUCH:
113 case WLR_INPUT_DEVICE_TABLET_PAD:
114 case WLR_INPUT_DEVICE_TABLET_TOOL:
115 sway_log(L_DEBUG, "TODO: configure other devices");
116 break;
117 }
118}
119
120void sway_seat_add_device(struct sway_seat *seat,
121 struct sway_input_device *input_device) {
122 if (sway_seat_get_device(seat, input_device)) {
123 sway_seat_configure_device(seat, input_device);
124 return;
125 }
126
127 struct sway_seat_device *seat_device =
128 calloc(1, sizeof(struct sway_seat_device));
129 if (!seat_device) {
130 sway_log(L_DEBUG, "could not allocate seat device");
131 return;
132 }
133
134 sway_log(L_DEBUG, "adding device %s to seat %s",
135 input_device->identifier, seat->wlr_seat->name);
136
137 seat_device->sway_seat = seat;
138 seat_device->input_device = input_device;
139 wl_list_insert(&seat->devices, &seat_device->link);
140
141 sway_seat_configure_device(seat, input_device);
142}
143
144void sway_seat_remove_device(struct sway_seat *seat,
145 struct sway_input_device *input_device) {
146 struct sway_seat_device *seat_device =
147 sway_seat_get_device(seat, input_device);
148
149 if (!seat_device) {
150 return;
151 }
152
153 sway_log(L_DEBUG, "removing device %s from seat %s",
154 input_device->identifier, seat->wlr_seat->name);
155
156 seat_device_destroy(seat_device);
157}
158
159void sway_seat_configure_xcursor(struct sway_seat *seat) {
160 // TODO configure theme and size
161 const char *cursor_theme = "default";
162
163 if (!seat->cursor->xcursor_manager) {
164 seat->cursor->xcursor_manager =
165 wlr_xcursor_manager_create("default", 24);
166 if (sway_assert(seat->cursor->xcursor_manager,
167 "Cannot create XCursor manager for theme %s",
168 cursor_theme)) {
169 return;
170 }
171 }
172
173 for (int i = 0; i < root_container.children->length; ++i) {
174 swayc_t *output_container = root_container.children->items[i];
175 struct wlr_output *output =
176 output_container->sway_output->wlr_output;
177 bool result =
178 wlr_xcursor_manager_load(seat->cursor->xcursor_manager,
179 output->scale);
180
181 sway_assert(!result,
182 "Cannot load xcursor theme for output '%s' with scale %f",
183 // TODO: Fractional scaling
184 output->name, (double)output->scale);
185 }
186
187 wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager,
188 "left_ptr", seat->cursor->cursor);
189 wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x,
190 seat->cursor->cursor->y);
191}
192
193static void handle_focus_destroy(struct wl_listener *listener, void *data) {
194 struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy);
195 //swayc_t *container = data;
196
197 // TODO set new focus based on the state of the tree
198 sway_seat_set_focus(seat, NULL);
199}
200
201void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
202 swayc_t *last_focus = seat->focus;
203
204 if (last_focus == container) {
205 return;
206 }
207
208 if (last_focus) {
209 wl_list_remove(&seat->focus_destroy.link);
210 }
211
212 if (container) {
213 struct sway_view *view = container->sway_view;
214 view->iface.set_activated(view, true);
215 wl_signal_add(&container->events.destroy, &seat->focus_destroy);
216 seat->focus_destroy.notify = handle_focus_destroy;
217 wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface);
218 }
219
220 seat->focus = container;
221
222 if (last_focus &&
223 !sway_input_manager_has_focus(seat->input, last_focus)) {
224 struct sway_view *view = last_focus->sway_view;
225 view->iface.set_activated(view, false);
226
227 }
228}
229
230void sway_seat_set_config(struct sway_seat *seat,
231 struct seat_config *seat_config) {
232 // clear configs
233 seat->config = NULL;
234
235 struct sway_seat_device *seat_device = NULL;
236 wl_list_for_each(seat_device, &seat->devices, link) {
237 seat_device->attachment_config = NULL;
238 }
239
240 if (!seat_config) {
241 return;
242 }
243
244 // add configs
245 seat->config = seat_config;
246
247 wl_list_for_each(seat_device, &seat->devices, link) {
248 seat_device->attachment_config =
249 seat_config_get_attachment(seat_config,
250 seat_device->input_device->identifier);
251 }
252}
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..d4652a82 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,23 @@ 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
56See Also 98See Also
57-------- 99--------
58 100
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}