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 | 107 | ||||
-rw-r--r-- | sway/input/seat.c | 144 | ||||
-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 | 101 |
11 files changed, 404 insertions, 98 deletions
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 31210a5a..38795e14 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -74,7 +74,7 @@ struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, | |||
74 | struct sway_container *container); | 74 | struct sway_container *container); |
75 | 75 | ||
76 | struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, | 76 | struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, |
77 | enum sway_container_type type); | 77 | struct sway_container *container, enum sway_container_type type); |
78 | 78 | ||
79 | void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); | 79 | void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); |
80 | 80 | ||
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index aff2e58e..fa22ea75 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -90,37 +90,61 @@ struct sway_container { | |||
90 | } events; | 90 | } events; |
91 | }; | 91 | }; |
92 | 92 | ||
93 | // TODO make private and use the container-specific create functions | ||
94 | struct sway_container *container_create(enum sway_container_type type); | ||
95 | |||
93 | const char *container_type_to_str(enum sway_container_type type); | 96 | const char *container_type_to_str(enum sway_container_type type); |
94 | 97 | ||
95 | // TODO only one container create function and pass the type? | 98 | // TODO only one container create function and pass the type? |
96 | struct sway_container *container_output_create( | 99 | struct sway_container *container_output_create( |
97 | struct sway_output *sway_output); | 100 | struct sway_output *sway_output); |
98 | 101 | ||
99 | struct sway_container *container_workspace_create( | 102 | /** |
100 | struct sway_container *output, const char *name); | 103 | * Create a new container container. A container container can be a a child of |
104 | * a workspace container or another container container. | ||
105 | */ | ||
106 | struct sway_container *container_container_create(); | ||
101 | 107 | ||
102 | struct sway_container *container_view_create( | 108 | /** |
103 | struct sway_container *sibling, struct sway_view *sway_view); | 109 | * Create a new output. Outputs are children of the root container and have no |
110 | * order in the tree structure. | ||
111 | */ | ||
112 | struct sway_container *container_output_create(struct sway_output *sway_output); | ||
104 | 113 | ||
105 | struct sway_container *container_output_destroy(struct sway_container *output); | 114 | /** |
115 | * Create a new workspace container. Workspaces are children of an output | ||
116 | * container and are ordered alphabetically by name. | ||
117 | */ | ||
118 | struct sway_container *container_workspace_create(struct sway_container *output, const char *name); | ||
106 | 119 | ||
107 | struct sway_container *container_workspace_destroy( | 120 | /* |
108 | struct sway_container *workspace); | 121 | * Create a new view container. A view can be a child of a workspace container |
122 | * or a container container and are rendered in the order and structure of | ||
123 | * how they are attached to the tree. | ||
124 | */ | ||
125 | // TODO view containers should be created in a detached state. | ||
126 | struct sway_container *container_view_create( | ||
127 | struct sway_container *sibling, struct sway_view *sway_view); | ||
109 | 128 | ||
110 | struct sway_container *container_view_destroy(struct sway_container *view); | 129 | // TODO don't return the parent on destroy |
130 | struct sway_container *container_destroy(struct sway_container *container); | ||
111 | 131 | ||
112 | struct sway_container *container_destroy(struct sway_container *cont); | 132 | struct sway_container *container_workspace_destroy(struct sway_container *container); |
133 | struct sway_container *container_output_destroy(struct sway_container *container); | ||
134 | struct sway_container *container_view_destroy(struct sway_container *container); | ||
113 | 135 | ||
136 | // TODO move to layout.c | ||
114 | struct sway_container *container_set_layout(struct sway_container *container, | 137 | struct sway_container *container_set_layout(struct sway_container *container, |
115 | enum sway_container_layout layout); | 138 | enum sway_container_layout layout); |
116 | 139 | ||
140 | // TODO rename to container_descendants_for_each() | ||
117 | void container_descendants(struct sway_container *root, | 141 | void container_descendants(struct sway_container *root, |
118 | enum sway_container_type type, | 142 | enum sway_container_type type, |
119 | void (*func)(struct sway_container *item, void *data), void *data); | 143 | void (*func)(struct sway_container *item, void *data), void *data); |
120 | 144 | ||
121 | /** | 145 | /** |
122 | * Finds a container based on test criteria. Returns the first container that | 146 | * Search a container's descendants a container based on test criteria. Returns |
123 | * passes the test. | 147 | * the first container that passes the test. |
124 | */ | 148 | */ |
125 | struct sway_container *container_find(struct sway_container *container, | 149 | struct sway_container *container_find(struct sway_container *container, |
126 | bool (*test)(struct sway_container *view, void *data), void *data); | 150 | bool (*test)(struct sway_container *view, void *data), void *data); |
@@ -128,18 +152,21 @@ struct sway_container *container_find(struct sway_container *container, | |||
128 | /** | 152 | /** |
129 | * Finds a parent container with the given struct sway_containerype. | 153 | * Finds a parent container with the given struct sway_containerype. |
130 | */ | 154 | */ |
155 | // TODO rename to container_parent_of_type() | ||
131 | struct sway_container *container_parent(struct sway_container *container, | 156 | struct sway_container *container_parent(struct sway_container *container, |
132 | enum sway_container_type type); | 157 | enum sway_container_type type); |
133 | 158 | ||
134 | /** | 159 | /** |
135 | * Find a container at the given coordinates. | 160 | * Find a container at the given coordinates. Returns the the surface and |
161 | * surface-local coordinates of the given layout coordinates if the container | ||
162 | * is a view and the view contains a surface at those coordinates. | ||
136 | */ | 163 | */ |
137 | struct sway_container *container_at(struct sway_container *parent, | 164 | struct sway_container *container_at(struct sway_container *container, |
138 | double lx, double ly, struct wlr_surface **surface, | 165 | double lx, double ly, struct wlr_surface **surface, |
139 | double *sx, double *sy); | 166 | double *sx, double *sy); |
140 | 167 | ||
141 | /** | 168 | /** |
142 | * Apply the function for each child of the container breadth first. | 169 | * Apply the function for each descendant of the container breadth first. |
143 | */ | 170 | */ |
144 | void container_for_each_descendant_bfs(struct sway_container *container, | 171 | void container_for_each_descendant_bfs(struct sway_container *container, |
145 | void (*f)(struct sway_container *container, void *data), void *data); | 172 | void (*f)(struct sway_container *container, void *data), void *data); |
@@ -150,7 +177,16 @@ void container_for_each_descendant_bfs(struct sway_container *container, | |||
150 | void container_for_each_descendant_dfs(struct sway_container *container, | 177 | void container_for_each_descendant_dfs(struct sway_container *container, |
151 | void (*f)(struct sway_container *container, void *data), void *data); | 178 | void (*f)(struct sway_container *container, void *data), void *data); |
152 | 179 | ||
153 | bool container_has_anscestor(struct sway_container *descendant, | 180 | /** |
181 | * Returns true if the given container is an ancestor of this container. | ||
182 | */ | ||
183 | bool container_has_anscestor(struct sway_container *container, | ||
154 | struct sway_container *anscestor); | 184 | struct sway_container *anscestor); |
155 | 185 | ||
186 | /** | ||
187 | * Returns true if the given container is a child descendant of this container. | ||
188 | */ | ||
189 | bool container_has_child(struct sway_container *con, | ||
190 | struct sway_container *child); | ||
191 | |||
156 | #endif | 192 | #endif |
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index e1034657..fbc3d6af 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 b6af3d1a..90012c6d 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..6df20e88 --- /dev/null +++ b/sway/commands/split.c | |||
@@ -0,0 +1,107 @@ | |||
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 argc, char **argv, int layout) { | ||
12 | char *name = layout == L_VERT ? "splitv" : | ||
13 | layout == L_HORIZ ? "splith" : "split"; | ||
14 | struct cmd_results *error = NULL; | ||
15 | if (config->reading) { | ||
16 | return cmd_results_new(CMD_FAILURE, name, | ||
17 | "Can't be used in config file."); | ||
18 | } | ||
19 | if (!config->active) { | ||
20 | return cmd_results_new(CMD_FAILURE, name, | ||
21 | "Can only be used when sway is running."); | ||
22 | } | ||
23 | if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) { | ||
24 | return error; | ||
25 | } | ||
26 | |||
27 | struct sway_container *focused = config->handler_context.current_container; | ||
28 | |||
29 | // TODO floating: dont split | ||
30 | |||
31 | /* Case that focus is on an workspace with 0/1 children.change its layout */ | ||
32 | if (focused->type == C_WORKSPACE && focused->children->length <= 1) { | ||
33 | wlr_log(L_DEBUG, "changing workspace layout"); | ||
34 | container_set_layout(focused, layout); | ||
35 | } else if (focused->type != C_WORKSPACE && | ||
36 | focused->parent->children->length == 1) { | ||
37 | /* Case of no siblings. change parent layout */ | ||
38 | wlr_log(L_DEBUG, "changing container layout"); | ||
39 | container_set_layout(focused->parent, layout); | ||
40 | } else { | ||
41 | // regular case where new split container is build around focused | ||
42 | // container or in case of workspace, container inherits its children | ||
43 | wlr_log(L_DEBUG, | ||
44 | "Adding new container around current focused container"); | ||
45 | wlr_log(L_INFO, "FOCUSED SIZE: %.f %.f", | ||
46 | focused->width, focused->height); | ||
47 | |||
48 | struct sway_container *parent = container_split(focused, layout); | ||
49 | arrange_windows(parent, -1, -1); | ||
50 | } | ||
51 | |||
52 | // TODO borders: update borders | ||
53 | |||
54 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
55 | } | ||
56 | |||
57 | struct cmd_results *cmd_split(int argc, char **argv) { | ||
58 | struct cmd_results *error = NULL; | ||
59 | if (config->reading) { | ||
60 | return cmd_results_new(CMD_FAILURE, "split", | ||
61 | "Can't be used in config file."); | ||
62 | } | ||
63 | if (!config->active) { | ||
64 | return cmd_results_new(CMD_FAILURE, "split", | ||
65 | "Can only be used when sway is running."); | ||
66 | } | ||
67 | if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { | ||
68 | return error; | ||
69 | } | ||
70 | if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { | ||
71 | _do_split(argc - 1, argv + 1, L_VERT); | ||
72 | } else if (strcasecmp(argv[0], "h") == 0 || | ||
73 | strcasecmp(argv[0], "horizontal") == 0) { | ||
74 | _do_split(argc - 1, argv + 1, L_HORIZ); | ||
75 | } else if (strcasecmp(argv[0], "t") == 0 || | ||
76 | strcasecmp(argv[0], "toggle") == 0) { | ||
77 | struct sway_container *focused = | ||
78 | config->handler_context.current_container; | ||
79 | if (focused->parent->layout == L_VERT) { | ||
80 | _do_split(argc - 1, argv + 1, L_HORIZ); | ||
81 | } else { | ||
82 | _do_split(argc - 1, argv + 1, L_VERT); | ||
83 | } | ||
84 | } else { | ||
85 | error = cmd_results_new(CMD_FAILURE, "split", | ||
86 | "Invalid split command (expected either horizontal or vertical)."); | ||
87 | return error; | ||
88 | } | ||
89 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
90 | } | ||
91 | |||
92 | struct cmd_results *cmd_splitv(int argc, char **argv) { | ||
93 | return _do_split(argc, argv, L_VERT); | ||
94 | } | ||
95 | |||
96 | struct cmd_results *cmd_splith(int argc, char **argv) { | ||
97 | return _do_split(argc, argv, L_HORIZ); | ||
98 | } | ||
99 | |||
100 | struct cmd_results *cmd_splitt(int argc, char **argv) { | ||
101 | struct sway_container *focused = config->handler_context.current_container; | ||
102 | if (focused->parent->layout == L_VERT) { | ||
103 | return _do_split(argc, argv, L_HORIZ); | ||
104 | } else { | ||
105 | return _do_split(argc, argv, L_VERT); | ||
106 | } | ||
107 | } | ||
diff --git a/sway/input/seat.c b/sway/input/seat.c index 9aa34aca..a1b1caa8 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> |
@@ -26,6 +27,7 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) { | |||
26 | } | 27 | } |
27 | 28 | ||
28 | void sway_seat_destroy(struct sway_seat *seat) { | 29 | void sway_seat_destroy(struct sway_seat *seat) { |
30 | // TODO destroy seat containers | ||
29 | struct sway_seat_device *seat_device, *next; | 31 | struct sway_seat_device *seat_device, *next; |
30 | wl_list_for_each_safe(seat_device, next, &seat->devices, link) { | 32 | wl_list_for_each_safe(seat_device, next, &seat->devices, link) { |
31 | seat_device_destroy(seat_device); | 33 | seat_device_destroy(seat_device); |
@@ -35,30 +37,90 @@ void sway_seat_destroy(struct sway_seat *seat) { | |||
35 | wlr_seat_destroy(seat->wlr_seat); | 37 | wlr_seat_destroy(seat->wlr_seat); |
36 | } | 38 | } |
37 | 39 | ||
40 | static struct sway_seat_container *seat_container_from_container( | ||
41 | struct sway_seat *seat, struct sway_container *con); | ||
42 | |||
43 | static void seat_container_destroy(struct sway_seat_container *seat_con) { | ||
44 | struct sway_container *con = seat_con->container; | ||
45 | struct sway_container *child = NULL; | ||
46 | |||
47 | if (con->children != NULL) { | ||
48 | for (int i = 0; i < con->children->length; ++i) { | ||
49 | child = con->children->items[i]; | ||
50 | struct sway_seat_container *seat_child = | ||
51 | seat_container_from_container(seat_con->seat, child); | ||
52 | seat_container_destroy(seat_child); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | wl_list_remove(&seat_con->destroy.link); | ||
57 | wl_list_remove(&seat_con->link); | ||
58 | free(seat_con); | ||
59 | } | ||
60 | |||
61 | static void seat_send_focus(struct sway_seat *seat, | ||
62 | struct sway_container *con) { | ||
63 | if (con->type != C_VIEW) { | ||
64 | return; | ||
65 | } | ||
66 | struct sway_view *view = con->sway_view; | ||
67 | if (view->type == SWAY_XWAYLAND_VIEW) { | ||
68 | struct wlr_xwayland *xwayland = | ||
69 | seat->input->server->xwayland; | ||
70 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | ||
71 | } | ||
72 | view_set_activated(view, true); | ||
73 | struct wlr_keyboard *keyboard = | ||
74 | wlr_seat_get_keyboard(seat->wlr_seat); | ||
75 | if (keyboard) { | ||
76 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | ||
77 | view->surface, keyboard->keycodes, | ||
78 | keyboard->num_keycodes, &keyboard->modifiers); | ||
79 | } else { | ||
80 | wlr_seat_keyboard_notify_enter( | ||
81 | seat->wlr_seat, view->surface, NULL, 0, NULL); | ||
82 | } | ||
83 | |||
84 | } | ||
85 | |||
38 | static void handle_seat_container_destroy(struct wl_listener *listener, | 86 | static void handle_seat_container_destroy(struct wl_listener *listener, |
39 | void *data) { | 87 | void *data) { |
40 | struct sway_seat_container *seat_con = | 88 | struct sway_seat_container *seat_con = |
41 | wl_container_of(listener, seat_con, destroy); | 89 | wl_container_of(listener, seat_con, destroy); |
42 | struct sway_seat *seat = seat_con->seat; | 90 | struct sway_seat *seat = seat_con->seat; |
43 | struct sway_container *con = seat_con->container; | 91 | struct sway_container *con = seat_con->container; |
92 | struct sway_container *parent = con->parent; | ||
93 | struct sway_container *focus = sway_seat_get_focus(seat); | ||
44 | 94 | ||
45 | bool is_focus = (sway_seat_get_focus(seat) == con); | 95 | // TODO handle workspace switch in the seat? |
96 | bool set_focus = | ||
97 | focus != NULL && | ||
98 | (focus == con || container_has_child(con, focus)) && | ||
99 | con->type != C_WORKSPACE; | ||
46 | 100 | ||
47 | wl_list_remove(&seat_con->link); | 101 | seat_container_destroy(seat_con); |
48 | 102 | ||
49 | if (is_focus) { | 103 | if (set_focus) { |
50 | // pick next focus | 104 | struct sway_container *next_focus = NULL; |
51 | sway_seat_set_focus(seat, NULL); | 105 | while (next_focus == NULL) { |
52 | struct sway_container *next = sway_seat_get_focus_inactive(seat, con->parent); | 106 | next_focus = sway_seat_get_focus_by_type(seat, parent, C_VIEW); |
53 | if (next == NULL) { | ||
54 | next = con->parent; | ||
55 | } | ||
56 | sway_seat_set_focus(seat, next); | ||
57 | } | ||
58 | 107 | ||
59 | wl_list_remove(&seat_con->destroy.link); | 108 | if (next_focus == NULL && parent->type == C_WORKSPACE) { |
109 | next_focus = parent; | ||
110 | break; | ||
111 | } | ||
60 | 112 | ||
61 | free(seat_con); | 113 | parent = parent->parent; |
114 | } | ||
115 | |||
116 | // the structure change might have caused it to move up to the top of | ||
117 | // the focus stack without sending focus notifications to the view | ||
118 | if (sway_seat_get_focus(seat) == next_focus) { | ||
119 | seat_send_focus(seat, next_focus); | ||
120 | } else { | ||
121 | sway_seat_set_focus(seat, next_focus); | ||
122 | } | ||
123 | } | ||
62 | } | 124 | } |
63 | 125 | ||
64 | static struct sway_seat_container *seat_container_from_container( | 126 | static struct sway_seat_container *seat_container_from_container( |
@@ -311,23 +373,7 @@ void sway_seat_set_focus_warp(struct sway_seat *seat, | |||
311 | wl_list_insert(&seat->focus_stack, &seat_con->link); | 373 | wl_list_insert(&seat->focus_stack, &seat_con->link); |
312 | 374 | ||
313 | if (container->type == C_VIEW) { | 375 | if (container->type == C_VIEW) { |
314 | struct sway_view *view = container->sway_view; | 376 | seat_send_focus(seat, container); |
315 | view_set_activated(view, true); | ||
316 | if (view->type == SWAY_XWAYLAND_VIEW) { | ||
317 | struct wlr_xwayland *xwayland = | ||
318 | seat->input->server->xwayland; | ||
319 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | ||
320 | } | ||
321 | struct wlr_keyboard *keyboard = | ||
322 | wlr_seat_get_keyboard(seat->wlr_seat); | ||
323 | if (keyboard) { | ||
324 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | ||
325 | view->surface, keyboard->keycodes, | ||
326 | keyboard->num_keycodes, &keyboard->modifiers); | ||
327 | } else { | ||
328 | wlr_seat_keyboard_notify_enter( | ||
329 | seat->wlr_seat, view->surface, NULL, 0, NULL); | ||
330 | } | ||
331 | } | 377 | } |
332 | } | 378 | } |
333 | 379 | ||
@@ -377,18 +423,33 @@ void sway_seat_set_focus(struct sway_seat *seat, | |||
377 | sway_seat_set_focus_warp(seat, container, true); | 423 | sway_seat_set_focus_warp(seat, container, true); |
378 | } | 424 | } |
379 | 425 | ||
380 | struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container) { | 426 | struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, |
427 | struct sway_container *container) { | ||
428 | return sway_seat_get_focus_by_type(seat, container, C_TYPES); | ||
429 | } | ||
430 | |||
431 | struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { | ||
432 | if (!seat->has_focus) { | ||
433 | return NULL; | ||
434 | } | ||
435 | return sway_seat_get_focus_inactive(seat, &root_container); | ||
436 | } | ||
437 | |||
438 | struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, | ||
439 | struct sway_container *container, enum sway_container_type type) { | ||
381 | struct sway_seat_container *current = NULL; | 440 | struct sway_seat_container *current = NULL; |
382 | struct sway_container *parent = NULL; | 441 | struct sway_container *parent = NULL; |
383 | wl_list_for_each(current, &seat->focus_stack, link) { | 442 | wl_list_for_each(current, &seat->focus_stack, link) { |
384 | parent = current->container->parent; | 443 | parent = current->container->parent; |
385 | 444 | ||
386 | if (current->container == container) { | 445 | if (current->container == container && |
446 | (type == C_TYPES || container->type == type)) { | ||
387 | return current->container; | 447 | return current->container; |
388 | } | 448 | } |
389 | 449 | ||
390 | while (parent) { | 450 | while (parent) { |
391 | if (parent == container) { | 451 | if (parent == container && (type == C_TYPES || |
452 | current->container->type == type)) { | ||
392 | return current->container; | 453 | return current->container; |
393 | } | 454 | } |
394 | parent = parent->parent; | 455 | parent = parent->parent; |
@@ -398,23 +459,6 @@ struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, stru | |||
398 | return NULL; | 459 | return NULL; |
399 | } | 460 | } |
400 | 461 | ||
401 | struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { | ||
402 | if (!seat->has_focus) { | ||
403 | return NULL; | ||
404 | } | ||
405 | return sway_seat_get_focus_inactive(seat, &root_container); | ||
406 | } | ||
407 | |||
408 | struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, | ||
409 | enum sway_container_type type) { | ||
410 | struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); | ||
411 | if (focus->type == type) { | ||
412 | return focus; | ||
413 | } | ||
414 | |||
415 | return container_parent(focus, type); | ||
416 | } | ||
417 | |||
418 | void sway_seat_set_config(struct sway_seat *seat, | 462 | void sway_seat_set_config(struct sway_seat *seat, |
419 | struct seat_config *seat_config) { | 463 | struct seat_config *seat_config) { |
420 | // clear configs | 464 | // clear configs |
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 21fe3fb0..41ba973f 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_destroy(child); | ||
93 | list_del(cont->children, 0); | ||
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 | 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 a8941a40..83e4fe37 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> |
@@ -100,10 +101,12 @@ void container_add_child(struct sway_container *parent, | |||
100 | parent, parent->type, parent->width, parent->height); | 101 | parent, parent->type, parent->width, parent->height); |
101 | list_add(parent->children, child); | 102 | list_add(parent->children, child); |
102 | child->parent = parent; | 103 | child->parent = parent; |
104 | // TODO: set focus for this container? | ||
105 | sway_input_manager_set_focus(input_manager, child); | ||
103 | } | 106 | } |
104 | 107 | ||
105 | struct sway_container *container_reap_empty(struct sway_container *container) { | 108 | struct sway_container *container_reap_empty(struct sway_container *container) { |
106 | if (!sway_assert(container, "reaping null container")) { | 109 | if (container == NULL) { |
107 | return NULL; | 110 | return NULL; |
108 | } | 111 | } |
109 | wlr_log(L_DEBUG, "Reaping %p %s '%s'", container, | 112 | wlr_log(L_DEBUG, "Reaping %p %s '%s'", container, |
@@ -137,7 +140,7 @@ struct sway_container *container_remove_child(struct sway_container *child) { | |||
137 | } | 140 | } |
138 | } | 141 | } |
139 | child->parent = NULL; | 142 | child->parent = NULL; |
140 | return container_reap_empty(parent); | 143 | return parent; |
141 | } | 144 | } |
142 | 145 | ||
143 | void container_move_to(struct sway_container *container, | 146 | void container_move_to(struct sway_container *container, |
@@ -348,7 +351,12 @@ static void apply_horiz_layout(struct sway_container *container, | |||
348 | wlr_log(L_DEBUG, | 351 | wlr_log(L_DEBUG, |
349 | "Calculating arrangement for %p:%d (will scale %f by %f)", | 352 | "Calculating arrangement for %p:%d (will scale %f by %f)", |
350 | child, child->type, width, scale); | 353 | child, child->type, width, scale); |
351 | view_set_position(child->sway_view, child_x, y); | 354 | if (child->type == C_VIEW) { |
355 | view_set_position(child->sway_view, child_x, y); | ||
356 | } else { | ||
357 | child->x = child_x; | ||
358 | child->y = y; | ||
359 | } | ||
352 | 360 | ||
353 | if (i == end - 1) { | 361 | if (i == end - 1) { |
354 | double remaining_width = x + width - child_x; | 362 | double remaining_width = x + width - child_x; |
@@ -531,9 +539,9 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { | |||
531 | return NULL; | 539 | return NULL; |
532 | } | 540 | } |
533 | 541 | ||
534 | static struct sway_container *get_swayc_in_direction_under( | 542 | struct sway_container *container_get_in_direction( |
535 | struct sway_container *container, enum movement_direction dir, | 543 | struct sway_container *container, struct sway_seat *seat, |
536 | struct sway_seat *seat, struct sway_container *limit) { | 544 | enum movement_direction dir) { |
537 | if (dir == MOVE_CHILD) { | 545 | if (dir == MOVE_CHILD) { |
538 | return sway_seat_get_focus_inactive(seat, container); | 546 | return sway_seat_get_focus_inactive(seat, container); |
539 | } | 547 | } |
@@ -565,7 +573,6 @@ static struct sway_container *get_swayc_in_direction_under( | |||
565 | 573 | ||
566 | struct sway_container *wrap_candidate = NULL; | 574 | struct sway_container *wrap_candidate = NULL; |
567 | while (true) { | 575 | while (true) { |
568 | // Test if we can even make a difference here | ||
569 | bool can_move = false; | 576 | bool can_move = false; |
570 | int desired; | 577 | int desired; |
571 | int idx = index_child(container); | 578 | int idx = index_child(container); |
@@ -595,7 +602,7 @@ static struct sway_container *get_swayc_in_direction_under( | |||
595 | } | 602 | } |
596 | if (next->children && next->children->length) { | 603 | if (next->children && next->children->length) { |
597 | // TODO consider floating children as well | 604 | // TODO consider floating children as well |
598 | return sway_seat_get_focus_inactive(seat, next); | 605 | return sway_seat_get_focus_by_type(seat, next, C_VIEW); |
599 | } else { | 606 | } else { |
600 | return next; | 607 | return next; |
601 | } | 608 | } |
@@ -625,21 +632,22 @@ static struct sway_container *get_swayc_in_direction_under( | |||
625 | wrap_candidate = parent->children->items[0]; | 632 | wrap_candidate = parent->children->items[0]; |
626 | } | 633 | } |
627 | if (config->force_focus_wrapping) { | 634 | if (config->force_focus_wrapping) { |
628 | return wrap_candidate; | 635 | return sway_seat_get_focus_by_type(seat, wrap_candidate, C_VIEW); |
629 | } | 636 | } |
630 | } | 637 | } |
631 | } else { | 638 | } else { |
632 | wlr_log(L_DEBUG, | 639 | wlr_log(L_DEBUG, |
633 | "cont %d-%p dir %i sibling %d: %p", idx, | 640 | "cont %d-%p dir %i sibling %d: %p", idx, |
634 | container, dir, desired, parent->children->items[desired]); | 641 | container, dir, desired, parent->children->items[desired]); |
635 | return parent->children->items[desired]; | 642 | return sway_seat_get_focus_by_type(seat, |
643 | parent->children->items[desired], C_VIEW); | ||
636 | } | 644 | } |
637 | } | 645 | } |
638 | 646 | ||
639 | if (!can_move) { | 647 | if (!can_move) { |
640 | container = parent; | 648 | container = parent; |
641 | parent = parent->parent; | 649 | parent = parent->parent; |
642 | if (!parent || container == limit) { | 650 | if (!parent) { |
643 | // wrapping is the last chance | 651 | // wrapping is the last chance |
644 | return wrap_candidate; | 652 | return wrap_candidate; |
645 | } | 653 | } |
@@ -647,8 +655,71 @@ static struct sway_container *get_swayc_in_direction_under( | |||
647 | } | 655 | } |
648 | } | 656 | } |
649 | 657 | ||
650 | struct sway_container *container_get_in_direction( | 658 | struct sway_container *container_replace_child(struct sway_container *child, |
651 | struct sway_container *container, struct sway_seat *seat, | 659 | struct sway_container *new_child) { |
652 | enum movement_direction dir) { | 660 | struct sway_container *parent = child->parent; |
653 | return get_swayc_in_direction_under(container, dir, seat, NULL); | 661 | if (parent == NULL) { |
662 | return NULL; | ||
663 | } | ||
664 | int i = index_child(child); | ||
665 | |||
666 | // TODO floating | ||
667 | parent->children->items[i] = new_child; | ||
668 | new_child->parent = parent; | ||
669 | child->parent = NULL; | ||
670 | |||
671 | // Set geometry for new child | ||
672 | new_child->x = child->x; | ||
673 | new_child->y = child->y; | ||
674 | new_child->width = child->width; | ||
675 | new_child->height = child->height; | ||
676 | |||
677 | // reset geometry for child | ||
678 | child->width = 0; | ||
679 | child->height = 0; | ||
680 | |||
681 | return parent; | ||
682 | } | ||
683 | |||
684 | struct sway_container *container_split(struct sway_container *child, | ||
685 | enum sway_container_layout layout) { | ||
686 | // TODO floating: cannot split a floating container | ||
687 | if (!sway_assert(child, "child cannot be null")) { | ||
688 | return NULL; | ||
689 | } | ||
690 | struct sway_container *cont = container_create(C_CONTAINER); | ||
691 | |||
692 | wlr_log(L_DEBUG, "creating container %p around %p", cont, child); | ||
693 | |||
694 | cont->prev_layout = L_NONE; | ||
695 | cont->layout = layout; | ||
696 | cont->width = child->width; | ||
697 | cont->height = child->height; | ||
698 | cont->x = child->x; | ||
699 | cont->y = child->y; | ||
700 | |||
701 | /* Container inherits all of workspaces children, layout and whatnot */ | ||
702 | if (child->type == C_WORKSPACE) { | ||
703 | struct sway_container *workspace = child; | ||
704 | // reorder focus | ||
705 | int i; | ||
706 | for (i = 0; i < workspace->children->length; ++i) { | ||
707 | ((struct sway_container *)workspace->children->items[i])->parent = | ||
708 | cont; | ||
709 | } | ||
710 | |||
711 | // Swap children | ||
712 | list_t *tmp_list = workspace->children; | ||
713 | workspace->children = cont->children; | ||
714 | cont->children = tmp_list; | ||
715 | // add container to workspace chidren | ||
716 | container_add_child(workspace, cont); | ||
717 | // give them proper layouts | ||
718 | cont->layout = workspace->workspace_layout; | ||
719 | cont->prev_layout = workspace->prev_layout; | ||
720 | } else { // Or is built around container | ||
721 | container_replace_child(child, cont); | ||
722 | container_add_child(cont, child); | ||
723 | } | ||
724 | return cont; | ||
654 | } | 725 | } |