diff options
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; | |||
107 | sway_cmd cmd_hide_edge_borders; | 110 | sway_cmd cmd_hide_edge_borders; |
108 | sway_cmd cmd_include; | 111 | sway_cmd cmd_include; |
109 | sway_cmd cmd_input; | 112 | sway_cmd cmd_input; |
113 | sway_cmd cmd_seat; | ||
110 | sway_cmd cmd_ipc; | 114 | sway_cmd cmd_ipc; |
111 | sway_cmd cmd_kill; | 115 | sway_cmd cmd_kill; |
112 | sway_cmd cmd_layout; | 116 | sway_cmd cmd_layout; |
@@ -176,6 +180,7 @@ sway_cmd bar_colors_cmd_statusline; | |||
176 | sway_cmd bar_colors_cmd_focused_statusline; | 180 | sway_cmd bar_colors_cmd_focused_statusline; |
177 | sway_cmd bar_colors_cmd_urgent_workspace; | 181 | sway_cmd bar_colors_cmd_urgent_workspace; |
178 | 182 | ||
183 | sway_cmd input_cmd_seat; | ||
179 | sway_cmd input_cmd_accel_profile; | 184 | sway_cmd input_cmd_accel_profile; |
180 | sway_cmd input_cmd_click_method; | 185 | sway_cmd input_cmd_click_method; |
181 | sway_cmd input_cmd_drag_lock; | 186 | sway_cmd input_cmd_drag_lock; |
@@ -187,6 +192,14 @@ sway_cmd input_cmd_natural_scroll; | |||
187 | sway_cmd input_cmd_pointer_accel; | 192 | sway_cmd input_cmd_pointer_accel; |
188 | sway_cmd input_cmd_scroll_method; | 193 | sway_cmd input_cmd_scroll_method; |
189 | sway_cmd input_cmd_tap; | 194 | sway_cmd input_cmd_tap; |
195 | sway_cmd input_cmd_xkb_layout; | ||
196 | sway_cmd input_cmd_xkb_model; | ||
197 | sway_cmd input_cmd_xkb_options; | ||
198 | sway_cmd input_cmd_xkb_rules; | ||
199 | sway_cmd input_cmd_xkb_variant; | ||
200 | |||
201 | sway_cmd seat_cmd_fallback; | ||
202 | sway_cmd seat_cmd_attach; | ||
190 | 203 | ||
191 | sway_cmd cmd_ipc_cmd; | 204 | sway_cmd cmd_ipc_cmd; |
192 | sway_cmd cmd_ipc_events; | 205 | sway_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 | */ | ||
83 | struct 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 | */ | ||
91 | struct 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); | |||
358 | struct cmd_results *check_security_config(); | 382 | struct cmd_results *check_security_config(); |
359 | 383 | ||
360 | int input_identifier_cmp(const void *item, const void *data); | 384 | int input_identifier_cmp(const void *item, const void *data); |
385 | struct input_config *new_input_config(const char* identifier); | ||
361 | void merge_input_config(struct input_config *dst, struct input_config *src); | 386 | void merge_input_config(struct input_config *dst, struct input_config *src); |
362 | void apply_input_config(struct input_config *ic, struct libinput_device *dev); | ||
363 | void free_input_config(struct input_config *ic); | 387 | void free_input_config(struct input_config *ic); |
388 | void apply_input_config(struct input_config *input); | ||
389 | |||
390 | int seat_name_cmp(const void *item, const void *data); | ||
391 | struct seat_config *new_seat_config(const char* name); | ||
392 | void merge_seat_config(struct seat_config *dst, struct seat_config *src); | ||
393 | void free_seat_config(struct seat_config *ic); | ||
394 | struct seat_attachment_config *seat_attachment_config_new(); | ||
395 | struct seat_attachment_config *seat_config_get_attachment( | ||
396 | struct seat_config *seat_config, char *identifier); | ||
397 | void apply_seat_config(struct seat_config *seat); | ||
364 | 398 | ||
365 | int output_name_cmp(const void *item, const void *data); | 399 | int output_name_cmp(const void *item, const void *data); |
366 | struct output_config *new_output_config(); | 400 | struct 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 | ||
8 | typedef struct sway_container swayc_t; | 9 | typedef 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 | ||
128 | void swayc_descendants_of_type(swayc_t *root, enum swayc_types type, | 133 | void swayc_descendants_of_type(swayc_t *root, enum swayc_types type, |
@@ -137,4 +142,7 @@ swayc_t *destroy_view(swayc_t *view); | |||
137 | 142 | ||
138 | swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type); | 143 | swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type); |
139 | 144 | ||
145 | swayc_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 | |||
6 | struct 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 | |||
28 | struct 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 | |||
8 | extern struct input_config *current_input_config; | ||
9 | extern struct seat_config *current_seat_config; | ||
10 | |||
11 | /** | ||
12 | * The global singleton input manager | ||
13 | * TODO: make me not a global | ||
14 | */ | ||
15 | extern struct sway_input_manager *input_manager; | ||
16 | |||
17 | struct 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 | |||
24 | struct 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 | |||
32 | struct sway_input_manager *sway_input_manager_create( | ||
33 | struct sway_server *server); | ||
34 | |||
35 | bool sway_input_manager_has_focus(struct sway_input_manager *input, | ||
36 | swayc_t *container); | ||
37 | |||
38 | void sway_input_manager_set_focus(struct sway_input_manager *input, | ||
39 | swayc_t *container); | ||
40 | |||
41 | void sway_input_manager_configure_xcursor(struct sway_input_manager *input); | ||
42 | |||
43 | void sway_input_manager_apply_input_config(struct sway_input_manager *input, | ||
44 | struct input_config *input_config); | ||
45 | |||
46 | void 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 | |||
6 | struct 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 | |||
15 | struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, | ||
16 | struct sway_seat_device *device); | ||
17 | |||
18 | void sway_keyboard_configure(struct sway_keyboard *keyboard); | ||
19 | |||
20 | void 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 | |||
7 | struct 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 | |||
15 | struct 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 | |||
29 | struct sway_seat *sway_seat_create(struct sway_input_manager *input, | ||
30 | const char *seat_name); | ||
31 | |||
32 | void sway_seat_add_device(struct sway_seat *seat, | ||
33 | struct sway_input_device *device); | ||
34 | |||
35 | void sway_seat_configure_device(struct sway_seat *seat, | ||
36 | struct sway_input_device *device); | ||
37 | |||
38 | void sway_seat_remove_device(struct sway_seat *seat, | ||
39 | struct sway_input_device *device); | ||
40 | |||
41 | void sway_seat_configure_xcursor(struct sway_seat *seat); | ||
42 | |||
43 | void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container); | ||
44 | |||
45 | void 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') | |||
29 | pango = dependency('pango') | 29 | pango = dependency('pango') |
30 | pixman = dependency('pixman-1') | 30 | pixman = dependency('pixman-1') |
31 | libcap = dependency('libcap') | 31 | libcap = dependency('libcap') |
32 | libinput = dependency('libinput') | ||
32 | math = cc.find_library('m') | 33 | math = cc.find_library('m') |
33 | git = find_program('git', required: false) | 34 | git = find_program('git', required: false) |
34 | a2x = find_program('a2x', required: false) | 35 | a2x = 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 | ||
60 | void 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 | |||
77 | void 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 | ||
102 | static int handler_compare(const void *_a, const void *_b) { | 139 | static 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 | ||
146 | static 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 | ||
166 | static struct cmd_handler seat_handlers[] = { | ||
167 | { "attach", seat_cmd_attach }, | ||
168 | { "fallback", seat_cmd_fallback }, | ||
169 | }; | ||
170 | |||
108 | static struct cmd_handler *find_handler(char *line, enum cmd_status block) { | 171 | static 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
8 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
8 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
8 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
7 | struct 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 | |||
10 | struct 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 | |||
7 | struct 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 | ||
314 | static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { | 321 | static 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 | |||
403 | bool read_config(FILE *file, struct sway_config *config) { | 415 | bool 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 | |||
8 | struct 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 | |||
36 | void 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 | |||
93 | void free_input_config(struct input_config *ic) { | ||
94 | if (!ic) { | ||
95 | return; | ||
96 | } | ||
97 | free(ic->identifier); | ||
98 | free(ic); | ||
99 | } | ||
100 | |||
101 | int 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 | |||
7 | struct 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 | |||
30 | struct 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 | |||
40 | static void seat_attachment_config_free( | ||
41 | struct seat_attachment_config *attachment) { | ||
42 | free(attachment->identifier); | ||
43 | free(attachment); | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | static 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 | |||
59 | static 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 | |||
64 | void 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 | |||
99 | void 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 | |||
115 | int 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 | |||
121 | struct 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 | ||
16 | static void output_frame_view(swayc_t *view, void *data) { | 18 | static 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 | ||
12 | static bool assert_wl_shell(struct sway_view *view) { | 14 | static 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 | ||
12 | static bool assert_xdg(struct sway_view *view) { | 14 | static 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 | |||
14 | static 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 | |||
25 | static 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 | |||
40 | static 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 | |||
50 | static 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 | |||
61 | static 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 | |||
79 | static 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 | |||
87 | static 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 | |||
94 | static 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 | |||
101 | static 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 | |||
108 | static 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 | |||
115 | static 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 | |||
122 | static 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 | |||
130 | struct 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 | |||
17 | static const char *default_seat = "seat0"; | ||
18 | |||
19 | // TODO make me not global | ||
20 | struct sway_input_manager *input_manager; | ||
21 | |||
22 | struct input_config *current_input_config = NULL; | ||
23 | struct seat_config *current_seat_config = NULL; | ||
24 | |||
25 | static 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 | |||
37 | static inline int strlen_num(int num) { | ||
38 | if (num == 0) { | ||
39 | return 2; | ||
40 | } | ||
41 | return (int)((ceil(log10(abs(num)))+2)); | ||
42 | } | ||
43 | |||
44 | static 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 | |||
75 | static 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 | |||
86 | static 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 | |||
97 | static 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 | |||
159 | static 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 | |||
184 | struct 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 | |||
208 | bool 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 | |||
220 | void 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 | |||
228 | void 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 | |||
243 | void 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 | |||
299 | void 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 | |||
14 | struct input_config *current_input_config = NULL; | ||
15 | |||
16 | struct 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 | |||
24 | struct 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 | |||
52 | char *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 | |||
6 | static 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 | |||
18 | static 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 | |||
29 | struct 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 | |||
46 | void 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 | |||
107 | void 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 | |||
12 | static 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 | |||
24 | struct 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 | |||
58 | static 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 | |||
65 | static 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 | |||
80 | static 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 | |||
92 | void 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 | |||
120 | void 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 | |||
144 | void 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 | |||
159 | void 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 | |||
193 | static 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 | |||
201 | void 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 | |||
230 | void 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 | ||
160 | static void log_kernel() { | 160 | static 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 | ||
33 | executable( | 61 | executable( |
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 | ||
16 | bool server_init(struct sway_server *server) { | 17 | bool 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 | ///// |
2 | vim:set ts=4 sw=4 tw=82 noet: | 2 | vim:set ft=asciidoc ts=4 sw=4 tw=82 noet: |
3 | ///// | 3 | ///// |
4 | sway-input (5) | 4 | sway-input (5) |
5 | ============== | 5 | ============== |
@@ -11,12 +11,37 @@ sway-input - input configuration file and commands | |||
11 | Description | 11 | Description |
12 | ----------- | 12 | ----------- |
13 | 13 | ||
14 | Sway allows for configuration of libinput devices within the sway configuration file. | 14 | Sway allows for configuration of devices within the sway configuration file. |
15 | sway-input commands must be used inside an _input { }_ block in the config. | 15 | sway-input commands must be used inside an _input { }_ block in the config. |
16 | To obtain a list of available device identifiers, run **swaymsg -t get_inputs**. | 16 | To obtain a list of available device identifiers, run **swaymsg -t get_inputs**. |
17 | 17 | ||
18 | Commands | 18 | Input Commands |
19 | -------- | 19 | -------------- |
20 | |||
21 | Keyboard Configuration | ||
22 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | |||
24 | For 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 | |||
43 | Libinput 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 | ||
81 | Seat Configuration | ||
82 | ------------------ | ||
83 | |||
84 | Configure options for multiseat mode. sway-seat commands must be used inside a | ||
85 | _seat { }_ block in the config. | ||
86 | |||
87 | A _seat_ is a collection of input devices that act independently of each other. | ||
88 | Seats are identified by name and the default seat is _seat0_ if no seats are | ||
89 | configured. Each seat has an independent keyboard focus and a separate cursor that | ||
90 | is controlled by the pointer devices of the seat. This is useful for multiple | ||
91 | people using the desktop at the same time with their own devices (each sitting in | ||
92 | their 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 | |||
56 | See Also | 98 | See 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 | ///// |
2 | vim:set ts=4 sw=4 tw=82 noet: | 2 | vim: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 | |||
229 | swayc_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 | } | ||