diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-01-30 23:09:21 -0500 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2018-01-30 23:09:21 -0500 |
commit | b28602aa7425cf435150e6008624429737e037d3 (patch) | |
tree | dafe7d23c48457299f33803832f6b89e09a915ce /sway/tree/workspace.c | |
parent | Remove include/sway/old/ (diff) | |
download | sway-b28602aa7425cf435150e6008624429737e037d3.tar.gz sway-b28602aa7425cf435150e6008624429737e037d3.tar.zst sway-b28602aa7425cf435150e6008624429737e037d3.zip |
Implement workspaces
Diffstat (limited to 'sway/tree/workspace.c')
-rw-r--r-- | sway/tree/workspace.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index c37a873c..23c630b6 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -2,8 +2,20 @@ | |||
2 | #include <stdbool.h> | 2 | #include <stdbool.h> |
3 | #include <stdlib.h> | 3 | #include <stdlib.h> |
4 | #include <stdio.h> | 4 | #include <stdio.h> |
5 | #include <strings.h> | ||
5 | #include "sway/container.h" | 6 | #include "sway/container.h" |
7 | #include "sway/input/input-manager.h" | ||
8 | #include "sway/input/seat.h" | ||
9 | #include "sway/workspace.h" | ||
6 | #include "log.h" | 10 | #include "log.h" |
11 | #include "util.h" | ||
12 | |||
13 | char *prev_workspace_name = NULL; | ||
14 | struct workspace_by_number_data { | ||
15 | int len; | ||
16 | const char *cset; | ||
17 | const char *name; | ||
18 | }; | ||
7 | 19 | ||
8 | void next_name_map(swayc_t *ws, void *data) { | 20 | void next_name_map(swayc_t *ws, void *data) { |
9 | int *count = data; | 21 | int *count = data; |
@@ -24,3 +36,202 @@ char *workspace_next_name(const char *output_name) { | |||
24 | snprintf(name, len + 1, "%d", count); | 36 | snprintf(name, len + 1, "%d", count); |
25 | return name; | 37 | return name; |
26 | } | 38 | } |
39 | |||
40 | static bool _workspace_by_number(swayc_t *view, void *data) { | ||
41 | if (view->type != C_WORKSPACE) { | ||
42 | return false; | ||
43 | } | ||
44 | struct workspace_by_number_data *wbnd = data; | ||
45 | int a = strspn(view->name, wbnd->cset); | ||
46 | return a == wbnd->len && strncmp(view->name, wbnd->name, a) == 0; | ||
47 | } | ||
48 | |||
49 | swayc_t *workspace_by_number(const char* name) { | ||
50 | struct workspace_by_number_data wbnd = {0, "1234567890", name}; | ||
51 | wbnd.len = strspn(name, wbnd.cset); | ||
52 | if (wbnd.len <= 0) { | ||
53 | return NULL; | ||
54 | } | ||
55 | return swayc_by_test(&root_container, _workspace_by_number, (void *) &wbnd); | ||
56 | } | ||
57 | |||
58 | static bool _workspace_by_name(swayc_t *view, void *data) { | ||
59 | return (view->type == C_WORKSPACE) && | ||
60 | (strcasecmp(view->name, (char *) data) == 0); | ||
61 | } | ||
62 | |||
63 | swayc_t *workspace_by_name(const char *name) { | ||
64 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
65 | swayc_t *current_workspace = NULL, *current_output = NULL; | ||
66 | if (seat->focus) { | ||
67 | current_workspace = swayc_parent_by_type(seat->focus, C_WORKSPACE); | ||
68 | current_output = swayc_parent_by_type(seat->focus, C_OUTPUT); | ||
69 | } | ||
70 | if (strcmp(name, "prev") == 0) { | ||
71 | return workspace_prev(current_workspace); | ||
72 | } else if (strcmp(name, "prev_on_output") == 0) { | ||
73 | return workspace_output_prev(current_output); | ||
74 | } else if (strcmp(name, "next") == 0) { | ||
75 | return workspace_next(current_workspace); | ||
76 | } else if (strcmp(name, "next_on_output") == 0) { | ||
77 | return workspace_output_next(current_output); | ||
78 | } else if (strcmp(name, "current") == 0) { | ||
79 | return current_workspace; | ||
80 | } else { | ||
81 | return swayc_by_test(&root_container, _workspace_by_name, (void *) name); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | swayc_t *workspace_create(const char *name) { | ||
86 | swayc_t *parent; | ||
87 | // Search for workspace<->output pair | ||
88 | int i, e = config->workspace_outputs->length; | ||
89 | for (i = 0; i < e; ++i) { | ||
90 | struct workspace_output *wso = config->workspace_outputs->items[i]; | ||
91 | if (strcasecmp(wso->workspace, name) == 0) { | ||
92 | // Find output to use if it exists | ||
93 | e = root_container.children->length; | ||
94 | for (i = 0; i < e; ++i) { | ||
95 | parent = root_container.children->items[i]; | ||
96 | if (strcmp(parent->name, wso->output) == 0) { | ||
97 | return new_workspace(parent, name); | ||
98 | } | ||
99 | } | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | // Otherwise create a new one | ||
104 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
105 | parent = seat->focus; | ||
106 | parent = swayc_parent_by_type(parent, C_OUTPUT); | ||
107 | return new_workspace(parent, name); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * Get the previous or next workspace on the specified output. Wraps around at | ||
112 | * the end and beginning. If next is false, the previous workspace is returned, | ||
113 | * otherwise the next one is returned. | ||
114 | */ | ||
115 | swayc_t *workspace_output_prev_next_impl(swayc_t *output, bool next) { | ||
116 | if (!sway_assert(output->type == C_OUTPUT, | ||
117 | "Argument must be an output, is %d", output->type)) { | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | int i; | ||
122 | for (i = 0; i < output->children->length; i++) { | ||
123 | if (output->children->items[i] == output->focused) { | ||
124 | return output->children->items[ | ||
125 | wrap(i + (next ? 1 : -1), output->children->length)]; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | // Doesn't happen, at worst the for loop returns the previously active workspace | ||
130 | return NULL; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * Get the previous or next workspace. If the first/last workspace on an output | ||
135 | * is active, proceed to the previous/next output's previous/next workspace. If | ||
136 | * next is false, the previous workspace is returned, otherwise the next one is | ||
137 | * returned. | ||
138 | */ | ||
139 | swayc_t *workspace_prev_next_impl(swayc_t *workspace, bool next) { | ||
140 | if (!sway_assert(workspace->type == C_WORKSPACE, | ||
141 | "Argument must be a workspace, is %d", workspace->type)) { | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | swayc_t *current_output = workspace->parent; | ||
146 | int offset = next ? 1 : -1; | ||
147 | int start = next ? 0 : 1; | ||
148 | int end; | ||
149 | if (next) { | ||
150 | end = current_output->children->length - 1; | ||
151 | } else { | ||
152 | end = current_output->children->length; | ||
153 | } | ||
154 | int i; | ||
155 | for (i = start; i < end; i++) { | ||
156 | if (current_output->children->items[i] == workspace) { | ||
157 | return current_output->children->items[i + offset]; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | // Given workspace is the first/last on the output, jump to the previous/next output | ||
162 | int num_outputs = root_container.children->length; | ||
163 | for (i = 0; i < num_outputs; i++) { | ||
164 | if (root_container.children->items[i] == current_output) { | ||
165 | swayc_t *next_output = root_container.children->items[ | ||
166 | wrap(i + offset, num_outputs)]; | ||
167 | return workspace_output_prev_next_impl(next_output, next); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | // Doesn't happen, at worst the for loop returns the previously active workspace on the active output | ||
172 | return NULL; | ||
173 | } | ||
174 | |||
175 | swayc_t *workspace_output_next(swayc_t *current) { | ||
176 | return workspace_output_prev_next_impl(current, true); | ||
177 | } | ||
178 | |||
179 | swayc_t *workspace_next(swayc_t *current) { | ||
180 | return workspace_prev_next_impl(current, true); | ||
181 | } | ||
182 | |||
183 | swayc_t *workspace_output_prev(swayc_t *current) { | ||
184 | return workspace_output_prev_next_impl(current, false); | ||
185 | } | ||
186 | |||
187 | swayc_t *workspace_prev(swayc_t *current) { | ||
188 | return workspace_prev_next_impl(current, false); | ||
189 | } | ||
190 | |||
191 | bool workspace_switch(swayc_t *workspace) { | ||
192 | if (!workspace) { | ||
193 | return false; | ||
194 | } | ||
195 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
196 | if (!seat || !seat->focus) { | ||
197 | return false; | ||
198 | } | ||
199 | swayc_t *active_ws = seat->focus; | ||
200 | if (active_ws->type != C_WORKSPACE) { | ||
201 | swayc_parent_by_type(seat->focus, C_WORKSPACE); | ||
202 | } | ||
203 | |||
204 | if (config->auto_back_and_forth | ||
205 | && active_ws == workspace | ||
206 | && prev_workspace_name) { | ||
207 | swayc_t *new_ws = workspace_by_name(prev_workspace_name); | ||
208 | workspace = new_ws ? new_ws : workspace_create(prev_workspace_name); | ||
209 | } | ||
210 | |||
211 | if (!prev_workspace_name || (strcmp(prev_workspace_name, active_ws->name) | ||
212 | && active_ws != workspace)) { | ||
213 | free(prev_workspace_name); | ||
214 | prev_workspace_name = malloc(strlen(active_ws->name) + 1); | ||
215 | if (!prev_workspace_name) { | ||
216 | wlr_log(L_ERROR, "Unable to allocate previous workspace name"); | ||
217 | return false; | ||
218 | } | ||
219 | strcpy(prev_workspace_name, active_ws->name); | ||
220 | } | ||
221 | |||
222 | // TODO: Deal with sticky containers | ||
223 | |||
224 | wlr_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); | ||
225 | // TODO FOCUS: Focus the last view this seat had focused on this workspace | ||
226 | if (workspace->children->length) { | ||
227 | // TODO FOCUS: This is really fucking stupid | ||
228 | sway_seat_set_focus(seat, workspace->children->items[0]); | ||
229 | } else { | ||
230 | sway_seat_set_focus(seat, workspace); | ||
231 | } | ||
232 | swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); | ||
233 | // TODO FOCUS: take a look at this | ||
234 | output->focused = workspace; | ||
235 | arrange_windows(output, -1, -1); | ||
236 | return true; | ||
237 | } | ||