diff options
-rw-r--r-- | include/sway/input/seat.h | 2 | ||||
-rw-r--r-- | include/sway/tree/container.h | 66 | ||||
-rw-r--r-- | include/sway/tree/layout.h | 12 | ||||
-rw-r--r-- | sway/commands.c | 4 | ||||
-rw-r--r-- | sway/commands/kill.c | 27 | ||||
-rw-r--r-- | sway/commands/split.c | 76 | ||||
-rw-r--r-- | sway/input/seat.c | 134 | ||||
-rw-r--r-- | sway/main.c | 2 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/tree/container.c | 36 | ||||
-rw-r--r-- | sway/tree/layout.c | 111 |
11 files changed, 376 insertions, 95 deletions
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 5c3c2c4f..c780a52b 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -72,7 +72,7 @@ struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | |||
72 | struct sway_container *container); | 72 | struct sway_container *container); |
73 | 73 | ||
74 | struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | 74 | struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, |
75 | enum sway_container_type type); | 75 | struct sway_container *container, enum sway_container_type type); |
76 | 76 | ||
77 | void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config); | 77 | void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config); |
78 | 78 | ||
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index bd02197c..464f80c4 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -91,37 +91,61 @@ struct sway_container { | |||
91 | } events; | 91 | } events; |
92 | }; | 92 | }; |
93 | 93 | ||
94 | // TODO make private and use the container-specific create functions | ||
95 | struct sway_container *container_create(enum sway_container_type type); | ||
96 | |||
94 | const char *container_type_to_str(enum sway_container_type type); | 97 | const char *container_type_to_str(enum sway_container_type type); |
95 | 98 | ||
96 | // TODO only one container create function and pass the type? | 99 | // TODO only one container create function and pass the type? |
97 | struct sway_container *container_output_create( | 100 | struct sway_container *container_output_create( |
98 | struct sway_output *sway_output); | 101 | struct sway_output *sway_output); |
99 | 102 | ||
100 | struct sway_container *container_workspace_create( | 103 | /** |
101 | struct sway_container *output, const char *name); | 104 | * Create a new container container. A container container can be a a child of |
105 | * a workspace container or another container container. | ||
106 | */ | ||
107 | struct sway_container *container_container_create(); | ||
102 | 108 | ||
103 | struct sway_container *container_view_create( | 109 | /** |
104 | struct sway_container *sibling, struct sway_view *sway_view); | 110 | * Create a new output. Outputs are children of the root container and have no |
111 | * order in the tree structure. | ||
112 | */ | ||
113 | struct sway_container *container_output_create(struct sway_output *sway_output); | ||
105 | 114 | ||
106 | struct sway_container *container_output_destroy(struct sway_container *output); | 115 | /** |
116 | * Create a new workspace container. Workspaces are children of an output | ||
117 | * container and are ordered alphabetically by name. | ||
118 | */ | ||
119 | struct sway_container *container_workspace_create(struct sway_container *output, const char *name); | ||
107 | 120 | ||
108 | struct sway_container *container_workspace_destroy( | 121 | /* |
109 | struct sway_container *workspace); | 122 | * Create a new view container. A view can be a child of a workspace container |
123 | * or a container container and are rendered in the order and structure of | ||
124 | * how they are attached to the tree. | ||
125 | */ | ||
126 | // TODO view containers should be created in a detached state. | ||
127 | struct sway_container *container_view_create( | ||
128 | struct sway_container *sibling, struct sway_view *sway_view); | ||
110 | 129 | ||
111 | struct sway_container *container_view_destroy(struct sway_container *view); | 130 | // TODO don't return the parent on destroy |
131 | struct sway_container *container_destroy(struct sway_container *container); | ||
112 | 132 | ||
113 | struct sway_container *container_destroy(struct sway_container *cont); | 133 | struct sway_container *container_workspace_destroy(struct sway_container *container); |
134 | struct sway_container *container_output_destroy(struct sway_container *container); | ||
135 | struct sway_container *container_view_destroy(struct sway_container *container); | ||
114 | 136 | ||
137 | // TODO move to layout.c | ||
115 | struct sway_container *container_set_layout(struct sway_container *container, | 138 | struct sway_container *container_set_layout(struct sway_container *container, |
116 | enum sway_container_layout layout); | 139 | enum sway_container_layout layout); |
117 | 140 | ||
141 | // TODO rename to container_descendants_for_each() | ||
118 | void container_descendants(struct sway_container *root, | 142 | void container_descendants(struct sway_container *root, |
119 | enum sway_container_type type, | 143 | enum sway_container_type type, |
120 | void (*func)(struct sway_container *item, void *data), void *data); | 144 | void (*func)(struct sway_container *item, void *data), void *data); |
121 | 145 | ||
122 | /** | 146 | /** |
123 | * Finds a container based on test criteria. Returns the first container that | 147 | * Search a container's descendants a container based on test criteria. Returns |
124 | * passes the test. | 148 | * the first container that passes the test. |
125 | */ | 149 | */ |
126 | struct sway_container *container_find(struct sway_container *container, | 150 | struct sway_container *container_find(struct sway_container *container, |
127 | bool (*test)(struct sway_container *view, void *data), void *data); | 151 | bool (*test)(struct sway_container *view, void *data), void *data); |
@@ -129,18 +153,21 @@ struct sway_container *container_find(struct sway_container *container, | |||
129 | /** | 153 | /** |
130 | * Finds a parent container with the given struct sway_containerype. | 154 | * Finds a parent container with the given struct sway_containerype. |
131 | */ | 155 | */ |
156 | // TODO rename to container_parent_of_type() | ||
132 | struct sway_container *container_parent(struct sway_container *container, | 157 | struct sway_container *container_parent(struct sway_container *container, |
133 | enum sway_container_type type); | 158 | enum sway_container_type type); |
134 | 159 | ||
135 | /** | 160 | /** |
136 | * Find a container at the given coordinates. | 161 | * Find a container at the given coordinates. Returns the the surface and |
162 | * surface-local coordinates of the given layout coordinates if the container | ||
163 | * is a view and the view contains a surface at those coordinates. | ||
137 | */ | 164 | */ |
138 | struct sway_container *container_at(struct sway_container *parent, | 165 | struct sway_container *container_at(struct sway_container *container, |
139 | double lx, double ly, struct wlr_surface **surface, | 166 | double lx, double ly, struct wlr_surface **surface, |
140 | double *sx, double *sy); | 167 | double *sx, double *sy); |
141 | 168 | ||
142 | /** | 169 | /** |
143 | * Apply the function for each child of the container breadth first. | 170 | * Apply the function for each descendant of the container breadth first. |
144 | */ | 171 | */ |
145 | void container_for_each_descendant_bfs(struct sway_container *container, | 172 | void container_for_each_descendant_bfs(struct sway_container *container, |
146 | void (*f)(struct sway_container *container, void *data), void *data); | 173 | void (*f)(struct sway_container *container, void *data), void *data); |
@@ -151,7 +178,16 @@ void container_for_each_descendant_bfs(struct sway_container *container, | |||
151 | void container_for_each_descendant_dfs(struct sway_container *container, | 178 | void container_for_each_descendant_dfs(struct sway_container *container, |
152 | void (*f)(struct sway_container *container, void *data), void *data); | 179 | void (*f)(struct sway_container *container, void *data), void *data); |
153 | 180 | ||
154 | bool container_has_anscestor(struct sway_container *descendant, | 181 | /** |
182 | * Returns true if the given container is an ancestor of this container. | ||
183 | */ | ||
184 | bool container_has_anscestor(struct sway_container *container, | ||
155 | struct sway_container *anscestor); | 185 | struct sway_container *anscestor); |
156 | 186 | ||
187 | /** | ||
188 | * Returns true if the given container is a child descendant of this container. | ||
189 | */ | ||
190 | bool container_has_child(struct sway_container *con, | ||
191 | struct sway_container *child); | ||
192 | |||
157 | #endif | 193 | #endif |
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index a14152e8..8badb244 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h | |||
@@ -29,31 +29,43 @@ struct sway_root { | |||
29 | 29 | ||
30 | void layout_init(void); | 30 | void layout_init(void); |
31 | 31 | ||
32 | // TODO move to tree.h | ||
32 | void container_add_child(struct sway_container *parent, | 33 | void container_add_child(struct sway_container *parent, |
33 | struct sway_container *child); | 34 | struct sway_container *child); |
34 | 35 | ||
36 | // TODO move to tree.h | ||
35 | struct sway_container *container_add_sibling(struct sway_container *parent, | 37 | struct sway_container *container_add_sibling(struct sway_container *parent, |
36 | struct sway_container *child); | 38 | struct sway_container *child); |
37 | 39 | ||
40 | // TODO move to tree.h | ||
38 | struct sway_container *container_remove_child(struct sway_container *child); | 41 | struct sway_container *container_remove_child(struct sway_container *child); |
39 | 42 | ||
43 | // TODO PRIVATE in tree.h | ||
40 | struct sway_container *container_reap_empty(struct sway_container *container); | 44 | struct sway_container *container_reap_empty(struct sway_container *container); |
41 | 45 | ||
46 | // TODO move to tree.h | ||
42 | void container_move_to(struct sway_container* container, | 47 | void container_move_to(struct sway_container* container, |
43 | struct sway_container* destination); | 48 | struct sway_container* destination); |
44 | 49 | ||
45 | void container_move(struct sway_container *container, | 50 | void container_move(struct sway_container *container, |
46 | enum movement_direction dir, int move_amt); | 51 | enum movement_direction dir, int move_amt); |
47 | 52 | ||
53 | // TODO move to output.c | ||
48 | enum sway_container_layout container_get_default_layout( | 54 | enum sway_container_layout container_get_default_layout( |
49 | struct sway_container *output); | 55 | struct sway_container *output); |
50 | 56 | ||
57 | // TODO move to output.c | ||
51 | void container_sort_workspaces(struct sway_container *output); | 58 | void container_sort_workspaces(struct sway_container *output); |
52 | 59 | ||
53 | void arrange_windows(struct sway_container *container, | 60 | void arrange_windows(struct sway_container *container, |
54 | double width, double height); | 61 | double width, double height); |
55 | 62 | ||
63 | // TODO move to container.h | ||
56 | struct sway_container *container_get_in_direction(struct sway_container | 64 | struct sway_container *container_get_in_direction(struct sway_container |
57 | *container, struct sway_seat *seat, enum movement_direction dir); | 65 | *container, struct sway_seat *seat, enum movement_direction dir); |
58 | 66 | ||
67 | // TODO move to tree.h | ||
68 | struct sway_container *container_split(struct sway_container *child, | ||
69 | enum sway_container_layout layout); | ||
70 | |||
59 | #endif | 71 | #endif |
diff --git a/sway/commands.c b/sway/commands.c index 9ba252b0..8156a08e 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -164,6 +164,10 @@ static struct cmd_handler command_handlers[] = { | |||
164 | { "layout", cmd_layout }, | 164 | { "layout", cmd_layout }, |
165 | { "move", cmd_move }, | 165 | { "move", cmd_move }, |
166 | { "reload", cmd_reload }, | 166 | { "reload", cmd_reload }, |
167 | { "split", cmd_split }, | ||
168 | { "splith", cmd_splith }, | ||
169 | { "splitt", cmd_splitt }, | ||
170 | { "splitv", cmd_splitv }, | ||
167 | }; | 171 | }; |
168 | 172 | ||
169 | static int handler_compare(const void *_a, const void *_b) { | 173 | static int handler_compare(const void *_a, const void *_b) { |
diff --git a/sway/commands/kill.c b/sway/commands/kill.c index f6774767..46d6e98e 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c | |||
@@ -3,21 +3,28 @@ | |||
3 | #include "sway/input/input-manager.h" | 3 | #include "sway/input/input-manager.h" |
4 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
5 | #include "sway/tree/view.h" | 5 | #include "sway/tree/view.h" |
6 | #include "sway/tree/container.h" | ||
6 | #include "sway/commands.h" | 7 | #include "sway/commands.h" |
7 | 8 | ||
8 | struct cmd_results *cmd_kill(int argc, char **argv) { | 9 | struct cmd_results *cmd_kill(int argc, char **argv) { |
9 | enum sway_container_type type = config->handler_context.current_container->type; | 10 | struct sway_container *con = |
10 | if (type != C_VIEW && type != C_CONTAINER) { | 11 | config->handler_context.current_container; |
12 | |||
13 | switch (con->type) { | ||
14 | case C_ROOT: | ||
15 | case C_OUTPUT: | ||
16 | case C_WORKSPACE: | ||
17 | case C_TYPES: | ||
11 | return cmd_results_new(CMD_INVALID, NULL, | 18 | return cmd_results_new(CMD_INVALID, NULL, |
12 | "Can only kill views and containers with this command"); | 19 | "Can only kill views and containers with this command"); |
13 | } | 20 | break; |
14 | 21 | case C_CONTAINER: | |
15 | // TODO close arbitrary containers without a view | 22 | con = container_destroy(con); |
16 | struct sway_view *view = | 23 | arrange_windows(con, -1, -1); |
17 | config->handler_context.current_container->sway_view; | 24 | break; |
18 | 25 | case C_VIEW: | |
19 | if (view) { | 26 | view_close(con->sway_view); |
20 | view_close(view); | 27 | break; |
21 | } | 28 | } |
22 | 29 | ||
23 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 30 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/split.c b/sway/commands/split.c new file mode 100644 index 00000000..ab8565a9 --- /dev/null +++ b/sway/commands/split.c | |||
@@ -0,0 +1,76 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/commands.h" | ||
4 | #include "sway/tree/container.h" | ||
5 | #include "sway/tree/layout.h" | ||
6 | #include "sway/tree/view.h" | ||
7 | #include "sway/input/input-manager.h" | ||
8 | #include "sway/input/seat.h" | ||
9 | #include "log.h" | ||
10 | |||
11 | static struct cmd_results *do_split(int layout) { | ||
12 | struct sway_container *con = config->handler_context.current_container; | ||
13 | struct sway_container *parent = container_split(con, layout); | ||
14 | arrange_windows(parent, -1, -1); | ||
15 | |||
16 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
17 | } | ||
18 | |||
19 | struct cmd_results *cmd_split(int argc, char **argv) { | ||
20 | struct cmd_results *error = NULL; | ||
21 | if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { | ||
22 | return error; | ||
23 | } | ||
24 | if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { | ||
25 | do_split(L_VERT); | ||
26 | } else if (strcasecmp(argv[0], "h") == 0 || | ||
27 | strcasecmp(argv[0], "horizontal") == 0) { | ||
28 | do_split(L_HORIZ); | ||
29 | } else if (strcasecmp(argv[0], "t") == 0 || | ||
30 | strcasecmp(argv[0], "toggle") == 0) { | ||
31 | struct sway_container *focused = | ||
32 | config->handler_context.current_container; | ||
33 | |||
34 | if (focused->parent->layout == L_VERT) { | ||
35 | do_split(L_HORIZ); | ||
36 | } else { | ||
37 | do_split(L_VERT); | ||
38 | } | ||
39 | } else { | ||
40 | error = cmd_results_new(CMD_FAILURE, "split", | ||
41 | "Invalid split command (expected either horizontal or vertical)."); | ||
42 | return error; | ||
43 | } | ||
44 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
45 | } | ||
46 | |||
47 | struct cmd_results *cmd_splitv(int argc, char **argv) { | ||
48 | struct cmd_results *error = NULL; | ||
49 | if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) { | ||
50 | return error; | ||
51 | } | ||
52 | return do_split(L_VERT); | ||
53 | } | ||
54 | |||
55 | struct cmd_results *cmd_splith(int argc, char **argv) { | ||
56 | struct cmd_results *error = NULL; | ||
57 | if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) { | ||
58 | return error; | ||
59 | } | ||
60 | return do_split(L_HORIZ); | ||
61 | } | ||
62 | |||
63 | struct cmd_results *cmd_splitt(int argc, char **argv) { | ||
64 | struct cmd_results *error = NULL; | ||
65 | if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) { | ||
66 | return error; | ||
67 | } | ||
68 | |||
69 | struct sway_container *con = config->handler_context.current_container; | ||
70 | |||
71 | if (con->parent->layout == L_VERT) { | ||
72 | return do_split(L_HORIZ); | ||
73 | } else { | ||
74 | return do_split(L_VERT); | ||
75 | } | ||
76 | } | ||
diff --git a/sway/input/seat.c b/sway/input/seat.c index 27636c1e..c41f7b2e 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _XOPEN_SOURCE 700 | 1 | #define _XOPEN_SOURCE 700 |
2 | #include <assert.h> | ||
2 | #include <wlr/types/wlr_cursor.h> | 3 | #include <wlr/types/wlr_cursor.h> |
3 | #include <wlr/types/wlr_output_layout.h> | 4 | #include <wlr/types/wlr_output_layout.h> |
4 | #include <wlr/types/wlr_xcursor_manager.h> | 5 | #include <wlr/types/wlr_xcursor_manager.h> |
@@ -35,31 +36,89 @@ void seat_destroy(struct sway_seat *seat) { | |||
35 | wlr_seat_destroy(seat->wlr_seat); | 36 | wlr_seat_destroy(seat->wlr_seat); |
36 | } | 37 | } |
37 | 38 | ||
39 | static struct sway_seat_container *seat_container_from_container( | ||
40 | struct sway_seat *seat, struct sway_container *con); | ||
41 | |||
42 | static void seat_container_destroy(struct sway_seat_container *seat_con) { | ||
43 | struct sway_container *con = seat_con->container; | ||
44 | struct sway_container *child = NULL; | ||
45 | |||
46 | if (con->children != NULL) { | ||
47 | for (int i = 0; i < con->children->length; ++i) { | ||
48 | child = con->children->items[i]; | ||
49 | struct sway_seat_container *seat_child = | ||
50 | seat_container_from_container(seat_con->seat, child); | ||
51 | seat_container_destroy(seat_child); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | wl_list_remove(&seat_con->destroy.link); | ||
56 | wl_list_remove(&seat_con->link); | ||
57 | free(seat_con); | ||
58 | } | ||
59 | |||
60 | static void seat_send_focus(struct sway_seat *seat, | ||
61 | struct sway_container *con) { | ||
62 | if (con->type != C_VIEW) { | ||
63 | return; | ||
64 | } | ||
65 | struct sway_view *view = con->sway_view; | ||
66 | if (view->type == SWAY_XWAYLAND_VIEW) { | ||
67 | struct wlr_xwayland *xwayland = | ||
68 | seat->input->server->xwayland; | ||
69 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | ||
70 | } | ||
71 | view_set_activated(view, true); | ||
72 | struct wlr_keyboard *keyboard = | ||
73 | wlr_seat_get_keyboard(seat->wlr_seat); | ||
74 | if (keyboard) { | ||
75 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | ||
76 | view->surface, keyboard->keycodes, | ||
77 | keyboard->num_keycodes, &keyboard->modifiers); | ||
78 | } else { | ||
79 | wlr_seat_keyboard_notify_enter( | ||
80 | seat->wlr_seat, view->surface, NULL, 0, NULL); | ||
81 | } | ||
82 | |||
83 | } | ||
84 | |||
38 | static void handle_seat_container_destroy(struct wl_listener *listener, | 85 | static void handle_seat_container_destroy(struct wl_listener *listener, |
39 | void *data) { | 86 | void *data) { |
40 | struct sway_seat_container *seat_con = | 87 | struct sway_seat_container *seat_con = |
41 | wl_container_of(listener, seat_con, destroy); | 88 | wl_container_of(listener, seat_con, destroy); |
42 | struct sway_seat *seat = seat_con->seat; | 89 | struct sway_seat *seat = seat_con->seat; |
43 | struct sway_container *con = seat_con->container; | 90 | struct sway_container *con = seat_con->container; |
91 | struct sway_container *parent = con->parent; | ||
92 | struct sway_container *focus = seat_get_focus(seat); | ||
44 | 93 | ||
45 | bool is_focus = (seat_get_focus(seat) == con); | 94 | bool set_focus = |
95 | focus != NULL && | ||
96 | (focus == con || container_has_child(con, focus)) && | ||
97 | con->type != C_WORKSPACE; | ||
46 | 98 | ||
47 | wl_list_remove(&seat_con->link); | 99 | seat_container_destroy(seat_con); |
48 | 100 | ||
49 | if (is_focus) { | 101 | if (set_focus) { |
50 | // pick next focus | 102 | struct sway_container *next_focus = NULL; |
51 | seat_set_focus(seat, NULL); | 103 | while (next_focus == NULL) { |
52 | struct sway_container *next = | 104 | next_focus = seat_get_focus_by_type(seat, parent, C_VIEW); |
53 | seat_get_focus_inactive(seat, con->parent); | ||
54 | if (next == NULL) { | ||
55 | next = con->parent; | ||
56 | } | ||
57 | seat_set_focus(seat, next); | ||
58 | } | ||
59 | 105 | ||
60 | wl_list_remove(&seat_con->destroy.link); | 106 | if (next_focus == NULL && parent->type == C_WORKSPACE) { |
107 | next_focus = parent; | ||
108 | break; | ||
109 | } | ||
61 | 110 | ||
62 | free(seat_con); | 111 | parent = parent->parent; |
112 | } | ||
113 | |||
114 | // the structure change might have caused it to move up to the top of | ||
115 | // the focus stack without sending focus notifications to the view | ||
116 | if (seat_get_focus(seat) == next_focus) { | ||
117 | seat_send_focus(seat, next_focus); | ||
118 | } else { | ||
119 | seat_set_focus(seat, next_focus); | ||
120 | } | ||
121 | } | ||
63 | } | 122 | } |
64 | 123 | ||
65 | static struct sway_seat_container *seat_container_from_container( | 124 | static struct sway_seat_container *seat_container_from_container( |
@@ -310,23 +369,7 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
310 | wl_list_insert(&seat->focus_stack, &seat_con->link); | 369 | wl_list_insert(&seat->focus_stack, &seat_con->link); |
311 | 370 | ||
312 | if (container->type == C_VIEW) { | 371 | if (container->type == C_VIEW) { |
313 | struct sway_view *view = container->sway_view; | 372 | seat_send_focus(seat, container); |
314 | view_set_activated(view, true); | ||
315 | if (view->type == SWAY_XWAYLAND_VIEW) { | ||
316 | struct wlr_xwayland *xwayland = | ||
317 | seat->input->server->xwayland; | ||
318 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | ||
319 | } | ||
320 | struct wlr_keyboard *keyboard = | ||
321 | wlr_seat_get_keyboard(seat->wlr_seat); | ||
322 | if (keyboard) { | ||
323 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | ||
324 | view->surface, keyboard->keycodes, | ||
325 | keyboard->num_keycodes, &keyboard->modifiers); | ||
326 | } else { | ||
327 | wlr_seat_keyboard_notify_enter( | ||
328 | seat->wlr_seat, view->surface, NULL, 0, NULL); | ||
329 | } | ||
330 | } | 373 | } |
331 | } | 374 | } |
332 | 375 | ||
@@ -378,17 +421,31 @@ void seat_set_focus(struct sway_seat *seat, | |||
378 | 421 | ||
379 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | 422 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, |
380 | struct sway_container *container) { | 423 | struct sway_container *container) { |
424 | return seat_get_focus_by_type(seat, container, C_TYPES); | ||
425 | } | ||
426 | |||
427 | struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { | ||
428 | if (!seat->has_focus) { | ||
429 | return NULL; | ||
430 | } | ||
431 | return seat_get_focus_inactive(seat, &root_container); | ||
432 | } | ||
433 | |||
434 | struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | ||
435 | struct sway_container *container, enum sway_container_type type) { | ||
381 | struct sway_seat_container *current = NULL; | 436 | struct sway_seat_container *current = NULL; |
382 | struct sway_container *parent = NULL; | 437 | struct sway_container *parent = NULL; |
383 | wl_list_for_each(current, &seat->focus_stack, link) { | 438 | wl_list_for_each(current, &seat->focus_stack, link) { |
384 | parent = current->container->parent; | 439 | parent = current->container->parent; |
385 | 440 | ||
386 | if (current->container == container) { | 441 | if (current->container == container && |
442 | (type == C_TYPES || container->type == type)) { | ||
387 | return current->container; | 443 | return current->container; |
388 | } | 444 | } |
389 | 445 | ||
390 | while (parent) { | 446 | while (parent) { |
391 | if (parent == container) { | 447 | if (parent == container && (type == C_TYPES || |
448 | current->container->type == type)) { | ||
392 | return current->container; | 449 | return current->container; |
393 | } | 450 | } |
394 | parent = parent->parent; | 451 | parent = parent->parent; |
@@ -405,17 +462,6 @@ struct sway_container *seat_get_focus(struct sway_seat *seat) { | |||
405 | return seat_get_focus_inactive(seat, &root_container); | 462 | return seat_get_focus_inactive(seat, &root_container); |
406 | } | 463 | } |
407 | 464 | ||
408 | struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | ||
409 | enum sway_container_type type) { | ||
410 | struct sway_container *focus = | ||
411 | seat_get_focus_inactive(seat, &root_container); | ||
412 | if (focus->type == type) { | ||
413 | return focus; | ||
414 | } | ||
415 | |||
416 | return container_parent(focus, type); | ||
417 | } | ||
418 | |||
419 | void seat_apply_config(struct sway_seat *seat, | 465 | void seat_apply_config(struct sway_seat *seat, |
420 | struct seat_config *seat_config) { | 466 | struct seat_config *seat_config) { |
421 | struct sway_seat_device *seat_device = NULL; | 467 | struct sway_seat_device *seat_device = NULL; |
diff --git a/sway/main.c b/sway/main.c index ded922ee..e7f8ddd3 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -118,7 +118,7 @@ void run_as_ipc_client(char *command, char *socket_path) { | |||
118 | static void log_env() { | 118 | static void log_env() { |
119 | const char *log_vars[] = { | 119 | const char *log_vars[] = { |
120 | "PATH", | 120 | "PATH", |
121 | "LD_LOAD_PATH", | 121 | "LD_LIBRARY_PATH", |
122 | "LD_PRELOAD_PATH", | 122 | "LD_PRELOAD_PATH", |
123 | "LD_LIBRARY_PATH", | 123 | "LD_LIBRARY_PATH", |
124 | "SWAY_CURSOR_THEME", | 124 | "SWAY_CURSOR_THEME", |
diff --git a/sway/meson.build b/sway/meson.build index 38945b4c..a6a633a0 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -19,6 +19,7 @@ sway_sources = files( | |||
19 | 'commands/input.c', | 19 | 'commands/input.c', |
20 | 'commands/layout.c', | 20 | 'commands/layout.c', |
21 | 'commands/mode.c', | 21 | 'commands/mode.c', |
22 | 'commands/split.c', | ||
22 | 'commands/move.c', | 23 | 'commands/move.c', |
23 | 'commands/seat.c', | 24 | 'commands/seat.c', |
24 | 'commands/seat/attach.c', | 25 | 'commands/seat/attach.c', |
diff --git a/sway/tree/container.c b/sway/tree/container.c index ea0b7d5c..4db93ce8 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -55,7 +55,7 @@ static void notify_new_container(struct sway_container *container) { | |||
55 | ipc_event_window(container, "new"); | 55 | ipc_event_window(container, "new"); |
56 | } | 56 | } |
57 | 57 | ||
58 | static struct sway_container *container_create(enum sway_container_type type) { | 58 | struct sway_container *container_create(enum sway_container_type type) { |
59 | // next id starts at 1 because 0 is assigned to root_container in layout.c | 59 | // next id starts at 1 because 0 is assigned to root_container in layout.c |
60 | static size_t next_id = 1; | 60 | static size_t next_id = 1; |
61 | struct sway_container *c = calloc(1, sizeof(struct sway_container)); | 61 | struct sway_container *c = calloc(1, sizeof(struct sway_container)); |
@@ -76,7 +76,7 @@ static struct sway_container *container_create(enum sway_container_type type) { | |||
76 | return c; | 76 | return c; |
77 | } | 77 | } |
78 | 78 | ||
79 | struct sway_container *container_destroy(struct sway_container *cont) { | 79 | static struct sway_container *_container_destroy(struct sway_container *cont) { |
80 | if (cont == NULL) { | 80 | if (cont == NULL) { |
81 | return NULL; | 81 | return NULL; |
82 | } | 82 | } |
@@ -84,13 +84,14 @@ struct sway_container *container_destroy(struct sway_container *cont) { | |||
84 | wl_signal_emit(&cont->events.destroy, cont); | 84 | wl_signal_emit(&cont->events.destroy, cont); |
85 | 85 | ||
86 | struct sway_container *parent = cont->parent; | 86 | struct sway_container *parent = cont->parent; |
87 | if (cont->children) { | 87 | if (cont->children != NULL) { |
88 | // remove children until there are no more, container_destroy calls | 88 | // remove children until there are no more, container_destroy calls |
89 | // container_remove_child, which removes child from this container | 89 | // container_remove_child, which removes child from this container |
90 | while (cont->children->length) { | 90 | while (cont->children != NULL && cont->children->length != 0) { |
91 | container_destroy(cont->children->items[0]); | 91 | struct sway_container *child = cont->children->items[0]; |
92 | container_remove_child(child); | ||
93 | container_destroy(child); | ||
92 | } | 94 | } |
93 | list_free(cont->children); | ||
94 | } | 95 | } |
95 | if (cont->marks) { | 96 | if (cont->marks) { |
96 | list_foreach(cont->marks, free); | 97 | list_foreach(cont->marks, free); |
@@ -102,10 +103,19 @@ struct sway_container *container_destroy(struct sway_container *cont) { | |||
102 | if (cont->name) { | 103 | if (cont->name) { |
103 | free(cont->name); | 104 | free(cont->name); |
104 | } | 105 | } |
106 | list_free(cont->children); | ||
107 | cont->children = NULL; | ||
105 | free(cont); | 108 | free(cont); |
106 | return parent; | 109 | return parent; |
107 | } | 110 | } |
108 | 111 | ||
112 | struct sway_container *container_destroy(struct sway_container *cont) { | ||
113 | struct sway_container *parent = _container_destroy(cont); | ||
114 | parent = container_reap_empty(parent); | ||
115 | arrange_windows(&root_container, -1, -1); | ||
116 | return parent; | ||
117 | } | ||
118 | |||
109 | struct sway_container *container_output_create( | 119 | struct sway_container *container_output_create( |
110 | struct sway_output *sway_output) { | 120 | struct sway_output *sway_output) { |
111 | struct wlr_box size; | 121 | struct wlr_box size; |
@@ -413,3 +423,17 @@ bool container_has_anscestor(struct sway_container *descendant, | |||
413 | } | 423 | } |
414 | return false; | 424 | return false; |
415 | } | 425 | } |
426 | |||
427 | static bool find_child_func(struct sway_container *con, void *data) { | ||
428 | struct sway_container *child = data; | ||
429 | return con == child; | ||
430 | } | ||
431 | |||
432 | bool container_has_child(struct sway_container *con, | ||
433 | struct sway_container *child) { | ||
434 | if (child == NULL || child->type == C_VIEW || | ||
435 | child->children->length == 0) { | ||
436 | return false; | ||
437 | } | ||
438 | return container_find(con, find_child_func, child); | ||
439 | } | ||
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 3333f9f1..95a84d12 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <assert.h> | ||
2 | #include <ctype.h> | 3 | #include <ctype.h> |
3 | #include <math.h> | 4 | #include <math.h> |
4 | #include <stdbool.h> | 5 | #include <stdbool.h> |
@@ -103,7 +104,7 @@ void container_add_child(struct sway_container *parent, | |||
103 | } | 104 | } |
104 | 105 | ||
105 | struct sway_container *container_reap_empty(struct sway_container *container) { | 106 | struct sway_container *container_reap_empty(struct sway_container *container) { |
106 | if (!sway_assert(container, "reaping null container")) { | 107 | if (container == NULL) { |
107 | return NULL; | 108 | return NULL; |
108 | } | 109 | } |
109 | wlr_log(L_DEBUG, "Reaping %p %s '%s'", container, | 110 | wlr_log(L_DEBUG, "Reaping %p %s '%s'", container, |
@@ -137,7 +138,7 @@ struct sway_container *container_remove_child(struct sway_container *child) { | |||
137 | } | 138 | } |
138 | } | 139 | } |
139 | child->parent = NULL; | 140 | child->parent = NULL; |
140 | return container_reap_empty(parent); | 141 | return parent; |
141 | } | 142 | } |
142 | 143 | ||
143 | void container_move_to(struct sway_container *container, | 144 | void container_move_to(struct sway_container *container, |
@@ -348,8 +349,14 @@ static void apply_horiz_layout(struct sway_container *container, | |||
348 | wlr_log(L_DEBUG, | 349 | wlr_log(L_DEBUG, |
349 | "Calculating arrangement for %p:%d (will scale %f by %f)", | 350 | "Calculating arrangement for %p:%d (will scale %f by %f)", |
350 | child, child->type, width, scale); | 351 | child, child->type, width, scale); |
351 | view_configure(child->sway_view, child_x, y, child->width, | 352 | |
352 | child->height); | 353 | if (child->type == C_VIEW) { |
354 | view_configure(child->sway_view, child_x, y, child->width, | ||
355 | child->height); | ||
356 | } else { | ||
357 | child->x = child_x; | ||
358 | child->y = y; | ||
359 | } | ||
353 | 360 | ||
354 | if (i == end - 1) { | 361 | if (i == end - 1) { |
355 | double remaining_width = x + width - child_x; | 362 | double remaining_width = x + width - child_x; |
@@ -400,8 +407,13 @@ void apply_vert_layout(struct sway_container *container, | |||
400 | wlr_log(L_DEBUG, | 407 | wlr_log(L_DEBUG, |
401 | "Calculating arrangement for %p:%d (will scale %f by %f)", | 408 | "Calculating arrangement for %p:%d (will scale %f by %f)", |
402 | child, child->type, height, scale); | 409 | child, child->type, height, scale); |
403 | view_configure(child->sway_view, x, child_y, child->width, | 410 | if (child->type == C_VIEW) { |
404 | child->height); | 411 | view_configure(child->sway_view, x, child_y, child->width, |
412 | child->height); | ||
413 | } else { | ||
414 | child->x = x; | ||
415 | child->y = child_y; | ||
416 | } | ||
405 | 417 | ||
406 | if (i == end - 1) { | 418 | if (i == end - 1) { |
407 | double remaining_height = y + height - child_y; | 419 | double remaining_height = y + height - child_y; |
@@ -533,9 +545,9 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { | |||
533 | return NULL; | 545 | return NULL; |
534 | } | 546 | } |
535 | 547 | ||
536 | static struct sway_container *get_swayc_in_direction_under( | 548 | struct sway_container *container_get_in_direction( |
537 | struct sway_container *container, enum movement_direction dir, | 549 | struct sway_container *container, struct sway_seat *seat, |
538 | struct sway_seat *seat, struct sway_container *limit) { | 550 | enum movement_direction dir) { |
539 | if (dir == MOVE_CHILD) { | 551 | if (dir == MOVE_CHILD) { |
540 | return seat_get_focus_inactive(seat, container); | 552 | return seat_get_focus_inactive(seat, container); |
541 | } | 553 | } |
@@ -567,7 +579,6 @@ static struct sway_container *get_swayc_in_direction_under( | |||
567 | 579 | ||
568 | struct sway_container *wrap_candidate = NULL; | 580 | struct sway_container *wrap_candidate = NULL; |
569 | while (true) { | 581 | while (true) { |
570 | // Test if we can even make a difference here | ||
571 | bool can_move = false; | 582 | bool can_move = false; |
572 | int desired; | 583 | int desired; |
573 | int idx = index_child(container); | 584 | int idx = index_child(container); |
@@ -597,7 +608,7 @@ static struct sway_container *get_swayc_in_direction_under( | |||
597 | } | 608 | } |
598 | if (next->children && next->children->length) { | 609 | if (next->children && next->children->length) { |
599 | // TODO consider floating children as well | 610 | // TODO consider floating children as well |
600 | return seat_get_focus_inactive(seat, next); | 611 | return seat_get_focus_by_type(seat, next, C_VIEW); |
601 | } else { | 612 | } else { |
602 | return next; | 613 | return next; |
603 | } | 614 | } |
@@ -627,21 +638,23 @@ static struct sway_container *get_swayc_in_direction_under( | |||
627 | wrap_candidate = parent->children->items[0]; | 638 | wrap_candidate = parent->children->items[0]; |
628 | } | 639 | } |
629 | if (config->force_focus_wrapping) { | 640 | if (config->force_focus_wrapping) { |
630 | return wrap_candidate; | 641 | return seat_get_focus_by_type(seat, |
642 | wrap_candidate, C_VIEW); | ||
631 | } | 643 | } |
632 | } | 644 | } |
633 | } else { | 645 | } else { |
634 | wlr_log(L_DEBUG, | 646 | wlr_log(L_DEBUG, |
635 | "cont %d-%p dir %i sibling %d: %p", idx, | 647 | "cont %d-%p dir %i sibling %d: %p", idx, |
636 | container, dir, desired, parent->children->items[desired]); | 648 | container, dir, desired, parent->children->items[desired]); |
637 | return parent->children->items[desired]; | 649 | return seat_get_focus_by_type(seat, |
650 | parent->children->items[desired], C_VIEW); | ||
638 | } | 651 | } |
639 | } | 652 | } |
640 | 653 | ||
641 | if (!can_move) { | 654 | if (!can_move) { |
642 | container = parent; | 655 | container = parent; |
643 | parent = parent->parent; | 656 | parent = parent->parent; |
644 | if (!parent || container == limit) { | 657 | if (!parent) { |
645 | // wrapping is the last chance | 658 | // wrapping is the last chance |
646 | return wrap_candidate; | 659 | return wrap_candidate; |
647 | } | 660 | } |
@@ -649,8 +662,70 @@ static struct sway_container *get_swayc_in_direction_under( | |||
649 | } | 662 | } |
650 | } | 663 | } |
651 | 664 | ||
652 | struct sway_container *container_get_in_direction( | 665 | struct sway_container *container_replace_child(struct sway_container *child, |
653 | struct sway_container *container, struct sway_seat *seat, | 666 | struct sway_container *new_child) { |
654 | enum movement_direction dir) { | 667 | struct sway_container *parent = child->parent; |
655 | return get_swayc_in_direction_under(container, dir, seat, NULL); | 668 | if (parent == NULL) { |
669 | return NULL; | ||
670 | } | ||
671 | int i = index_child(child); | ||
672 | |||
673 | // TODO floating | ||
674 | parent->children->items[i] = new_child; | ||
675 | new_child->parent = parent; | ||
676 | child->parent = NULL; | ||
677 | |||
678 | // Set geometry for new child | ||
679 | new_child->x = child->x; | ||
680 | new_child->y = child->y; | ||
681 | new_child->width = child->width; | ||
682 | new_child->height = child->height; | ||
683 | |||
684 | // reset geometry for child | ||
685 | child->width = 0; | ||
686 | child->height = 0; | ||
687 | |||
688 | return parent; | ||
689 | } | ||
690 | |||
691 | struct sway_container *container_split(struct sway_container *child, | ||
692 | enum sway_container_layout layout) { | ||
693 | // TODO floating: cannot split a floating container | ||
694 | if (!sway_assert(child, "child cannot be null")) { | ||
695 | return NULL; | ||
696 | } | ||
697 | struct sway_container *cont = container_create(C_CONTAINER); | ||
698 | |||
699 | wlr_log(L_DEBUG, "creating container %p around %p", cont, child); | ||
700 | |||
701 | cont->prev_layout = L_NONE; | ||
702 | cont->width = child->width; | ||
703 | cont->height = child->height; | ||
704 | cont->x = child->x; | ||
705 | cont->y = child->y; | ||
706 | |||
707 | if (child->type == C_WORKSPACE) { | ||
708 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | ||
709 | struct sway_container *workspace = child; | ||
710 | bool set_focus = (seat_get_focus(seat) == workspace); | ||
711 | |||
712 | while (workspace->children->length) { | ||
713 | struct sway_container *ws_child = workspace->children->items[0]; | ||
714 | container_remove_child(ws_child); | ||
715 | container_add_child(cont, ws_child); | ||
716 | } | ||
717 | |||
718 | container_add_child(workspace, cont); | ||
719 | container_set_layout(workspace, layout); | ||
720 | |||
721 | if (set_focus) { | ||
722 | seat_set_focus(seat, cont); | ||
723 | } | ||
724 | } else { | ||
725 | cont->layout = layout; | ||
726 | container_replace_child(child, cont); | ||
727 | container_add_child(cont, child); | ||
728 | } | ||
729 | |||
730 | return cont; | ||
656 | } | 731 | } |