summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--include/container.h11
-rw-r--r--include/input_state.h1
-rw-r--r--include/stringop.h1
-rw-r--r--sway-xorg.desktop5
-rw-r--r--sway.desktop5
-rw-r--r--sway/commands.c5
-rw-r--r--sway/config.c3
-rw-r--r--sway/container.c138
-rw-r--r--sway/handlers.c15
-rw-r--r--sway/input_state.c7
-rw-r--r--sway/ipc.c92
-rw-r--r--sway/layout.c10
-rw-r--r--sway/stringop.c39
-rw-r--r--sway/workspace.c4
15 files changed, 273 insertions, 71 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d190cd8b..3ed6fc02 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,3 +69,11 @@ INSTALL(
69 FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/sway.5 69 FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/sway.5
70 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man5 70 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man5
71) 71)
72
73INSTALL(
74 FILES ${PROJECT_SOURCE_DIR}/sway.desktop
75 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/wayland-sessions/)
76
77INSTALL(
78 FILES ${PROJECT_SOURCE_DIR}/sway-xorg.desktop
79 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/xsessions/)
diff --git a/include/container.h b/include/container.h
index d3026011..3598067c 100644
--- a/include/container.h
+++ b/include/container.h
@@ -55,6 +55,7 @@ struct sway_container {
55 struct sway_container *focused; 55 struct sway_container *focused;
56}; 56};
57 57
58// Container Creation
58 59
59swayc_t *new_output(wlc_handle handle); 60swayc_t *new_output(wlc_handle handle);
60swayc_t *new_workspace(swayc_t *output, const char *name); 61swayc_t *new_workspace(swayc_t *output, const char *name);
@@ -65,13 +66,23 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle);
65// Creates view as a new floating view which is in the active workspace 66// Creates view as a new floating view which is in the active workspace
66swayc_t *new_floating_view(wlc_handle handle); 67swayc_t *new_floating_view(wlc_handle handle);
67 68
69// Container Destroying
68 70
69swayc_t *destroy_output(swayc_t *output); 71swayc_t *destroy_output(swayc_t *output);
70// Destroys workspace if empty and returns parent pointer, else returns NULL 72// Destroys workspace if empty and returns parent pointer, else returns NULL
71swayc_t *destroy_workspace(swayc_t *workspace); 73swayc_t *destroy_workspace(swayc_t *workspace);
74// Destroyes container and all parent container if they are empty, returns
75// topmost non-empty parent. returns NULL otherwise
72swayc_t *destroy_container(swayc_t *container); 76swayc_t *destroy_container(swayc_t *container);
77// Destroys view and all empty parent containers. return topmost non-empty
78// parent
73swayc_t *destroy_view(swayc_t *view); 79swayc_t *destroy_view(swayc_t *view);
74 80
81// Container Lookup
82
83swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types);
84swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts);
85
75swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); 86swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
76void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); 87void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
77 88
diff --git a/include/input_state.h b/include/input_state.h
index 7119c68b..27dd6cff 100644
--- a/include/input_state.h
+++ b/include/input_state.h
@@ -48,6 +48,7 @@ extern struct pointer_state {
48 48
49void start_floating(swayc_t *view); 49void start_floating(swayc_t *view);
50void reset_floating(swayc_t *view); 50void reset_floating(swayc_t *view);
51void input_init(void);
51 52
52#endif 53#endif
53 54
diff --git a/include/stringop.h b/include/stringop.h
index a5346829..4300f9ed 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -10,5 +10,6 @@ char *code_strchr(const char *string, char delimiter);
10char *code_strstr(const char *haystack, const char *needle); 10char *code_strstr(const char *haystack, const char *needle);
11int unescape_string(char *string); 11int unescape_string(char *string);
12char *join_args(char **argv, int argc); 12char *join_args(char **argv, int argc);
13char *join_list(list_t *list, char *separator);
13 14
14#endif 15#endif
diff --git a/sway-xorg.desktop b/sway-xorg.desktop
new file mode 100644
index 00000000..e93a4284
--- /dev/null
+++ b/sway-xorg.desktop
@@ -0,0 +1,5 @@
1[Desktop Entry]
2Name=Sway (Xorg)
3Comment=SirCmpwn's Wayland window manager
4Exec=sway
5Type=Application
diff --git a/sway.desktop b/sway.desktop
new file mode 100644
index 00000000..98c9af29
--- /dev/null
+++ b/sway.desktop
@@ -0,0 +1,5 @@
1[Desktop Entry]
2Name=Sway
3Comment=SirCmpwn's Wayland window manager
4Exec=sway
5Type=Application
diff --git a/sway/commands.c b/sway/commands.c
index 0f743b4e..d1bbdc89 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -390,7 +390,6 @@ static bool cmd_layout(struct sway_config *config, int argc, char **argv) {
390 return false; 390 return false;
391 } 391 }
392 swayc_t *parent = get_focused_container(&root_container); 392 swayc_t *parent = get_focused_container(&root_container);
393
394 while (parent->type == C_VIEW) { 393 while (parent->type == C_VIEW) {
395 parent = parent->parent; 394 parent = parent->parent;
396 } 395 }
@@ -665,9 +664,7 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) {
665 // Resize workspace if going from fullscreen -> notfullscreen 664 // Resize workspace if going from fullscreen -> notfullscreen
666 // otherwise just resize container 665 // otherwise just resize container
667 if (current) { 666 if (current) {
668 while (container->type != C_WORKSPACE) { 667 container = swayc_parent_by_type(container, C_WORKSPACE);
669 container = container->parent;
670 }
671 } 668 }
672 // Only resize container when going into fullscreen 669 // Only resize container when going into fullscreen
673 arrange_windows(container, -1, -1); 670 arrange_windows(container, -1, -1);
diff --git a/sway/config.c b/sway/config.c
index 9f65e8a2..0afb0205 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -9,6 +9,7 @@
9#include "commands.h" 9#include "commands.h"
10#include "config.h" 10#include "config.h"
11#include "layout.h" 11#include "layout.h"
12#include "input_state.h"
12 13
13struct sway_config *config; 14struct sway_config *config;
14 15
@@ -147,6 +148,8 @@ _continue:
147bool load_config(const char *file) { 148bool load_config(const char *file) {
148 sway_log(L_INFO, "Loading config"); 149 sway_log(L_INFO, "Loading config");
149 150
151 input_init();
152
150 char *path; 153 char *path;
151 if (file != NULL) { 154 if (file != NULL) {
152 path = strdup(file); 155 path = strdup(file);
diff --git a/sway/container.c b/sway/container.c
index 4559a5f5..7ccc2e09 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -8,6 +8,8 @@
8#include "layout.h" 8#include "layout.h"
9#include "log.h" 9#include "log.h"
10 10
11#define ASSERT_NONNULL(PTR) \
12 sway_assert (PTR, "%s: " #PTR "must be non-null", __func__)
11 13
12static swayc_t *new_swayc(enum swayc_types type) { 14static swayc_t *new_swayc(enum swayc_types type) {
13 swayc_t *c = calloc(1, sizeof(swayc_t)); 15 swayc_t *c = calloc(1, sizeof(swayc_t));
@@ -20,37 +22,40 @@ static swayc_t *new_swayc(enum swayc_types type) {
20 return c; 22 return c;
21} 23}
22 24
23static void free_swayc(swayc_t *c) { 25static void free_swayc(swayc_t *cont) {
26 if (!ASSERT_NONNULL(cont)) {
27 return;
28 }
24 // TODO does not properly handle containers with children, 29 // TODO does not properly handle containers with children,
25 // TODO but functions that call this usually check for that 30 // TODO but functions that call this usually check for that
26 if (c->children) { 31 if (cont->children) {
27 if (c->children->length) { 32 if (cont->children->length) {
28 int i; 33 int i;
29 for (i = 0; i < c->children->length; ++i) { 34 for (i = 0; i < cont->children->length; ++i) {
30 free_swayc(c->children->items[i]); 35 free_swayc(cont->children->items[i]);
31 } 36 }
32 } 37 }
33 list_free(c->children); 38 list_free(cont->children);
34 } 39 }
35 if (c->floating) { 40 if (cont->floating) {
36 if (c->floating->length) { 41 if (cont->floating->length) {
37 int i; 42 int i;
38 for (i = 0; i < c->floating->length; ++i) { 43 for (i = 0; i < cont->floating->length; ++i) {
39 free_swayc(c->floating->items[i]); 44 free_swayc(cont->floating->items[i]);
40 } 45 }
41 } 46 }
42 list_free(c->floating); 47 list_free(cont->floating);
43 } 48 }
44 if (c->parent) { 49 if (cont->parent) {
45 remove_child(c); 50 remove_child(cont);
46 } 51 }
47 if (c->name) { 52 if (cont->name) {
48 free(c->name); 53 free(cont->name);
49 } 54 }
50 free(c); 55 free(cont);
51} 56}
52 57
53/* New containers */ 58// New containers
54 59
55static bool workspace_test(swayc_t *view, void *name) { 60static bool workspace_test(swayc_t *view, void *name) {
56 return strcasecmp(view->name, (char *)name) == 0; 61 return strcasecmp(view->name, (char *)name) == 0;
@@ -103,6 +108,9 @@ swayc_t *new_output(wlc_handle handle) {
103} 108}
104 109
105swayc_t *new_workspace(swayc_t *output, const char *name) { 110swayc_t *new_workspace(swayc_t *output, const char *name) {
111 if (!ASSERT_NONNULL(output)) {
112 return NULL;
113 }
106 sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle); 114 sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle);
107 swayc_t *workspace = new_swayc(C_WORKSPACE); 115 swayc_t *workspace = new_swayc(C_WORKSPACE);
108 116
@@ -120,6 +128,9 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
120} 128}
121 129
122swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { 130swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
131 if (!ASSERT_NONNULL(child)) {
132 return NULL;
133 }
123 swayc_t *cont = new_swayc(C_CONTAINER); 134 swayc_t *cont = new_swayc(C_CONTAINER);
124 135
125 sway_log(L_DEBUG, "creating container %p around %p", cont, child); 136 sway_log(L_DEBUG, "creating container %p around %p", cont, child);
@@ -162,6 +173,9 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
162} 173}
163 174
164swayc_t *new_view(swayc_t *sibling, wlc_handle handle) { 175swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
176 if (!ASSERT_NONNULL(sibling)) {
177 return NULL;
178 }
165 const char *title = wlc_view_get_title(handle); 179 const char *title = wlc_view_get_title(handle);
166 swayc_t *view = new_swayc(C_VIEW); 180 swayc_t *view = new_swayc(C_VIEW);
167 sway_log(L_DEBUG, "Adding new view %lu:%s to container %p %d", 181 sway_log(L_DEBUG, "Adding new view %lu:%s to container %p %d",
@@ -172,14 +186,14 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
172 view->visible = true; 186 view->visible = true;
173 view->is_focused = true; 187 view->is_focused = true;
174 // Setup geometry 188 // Setup geometry
189 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
175 view->width = 0; 190 view->width = 0;
176 view->height = 0; 191 view->height = 0;
192 view->desired_width = geometry->size.w;
193 view->desired_height = geometry->size.h;
177 194
178 view->gaps = config->gaps_inner; 195 view->gaps = config->gaps_inner;
179 196
180 view->desired_width = -1;
181 view->desired_height = -1;
182
183 view->is_floating = false; 197 view->is_floating = false;
184 198
185 if (sibling->type == C_WORKSPACE) { 199 if (sibling->type == C_WORKSPACE) {
@@ -225,9 +239,12 @@ swayc_t *new_floating_view(wlc_handle handle) {
225 return view; 239 return view;
226} 240}
227 241
228/* Destroy container */ 242// Destroy container
229 243
230swayc_t *destroy_output(swayc_t *output) { 244swayc_t *destroy_output(swayc_t *output) {
245 if (!ASSERT_NONNULL(output)) {
246 return NULL;
247 }
231 if (output->children->length == 0) { 248 if (output->children->length == 0) {
232 // TODO move workspaces to other outputs 249 // TODO move workspaces to other outputs
233 } 250 }
@@ -237,23 +254,21 @@ swayc_t *destroy_output(swayc_t *output) {
237} 254}
238 255
239swayc_t *destroy_workspace(swayc_t *workspace) { 256swayc_t *destroy_workspace(swayc_t *workspace) {
257 if (!ASSERT_NONNULL(workspace)) {
258 return NULL;
259 }
240 // NOTE: This is called from elsewhere without checking children length 260 // NOTE: This is called from elsewhere without checking children length
241 // TODO move containers to other workspaces? 261 // TODO move containers to other workspaces?
242 // for now just dont delete 262 // for now just dont delete
243 263
244 // Do not destroy this if it's the last workspace on this output 264 // Do not destroy this if it's the last workspace on this output
245 swayc_t *output = workspace->parent; 265 swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
246 while (output && output->type != C_OUTPUT) { 266 if (output && output->children->length == 1) {
247 output = output->parent; 267 return NULL;
248 }
249 if (output) {
250 if (output->children->length == 1) {
251 return NULL;
252 }
253 } 268 }
254 269
255 if (workspace->children->length == 0) { 270 if (workspace->children->length == 0) {
256 sway_log(L_DEBUG, "Workspace: Destroying workspace '%s'", workspace->name); 271 sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name);
257 swayc_t *parent = workspace->parent; 272 swayc_t *parent = workspace->parent;
258 free_swayc(workspace); 273 free_swayc(workspace);
259 return parent; 274 return parent;
@@ -262,6 +277,9 @@ swayc_t *destroy_workspace(swayc_t *workspace) {
262} 277}
263 278
264swayc_t *destroy_container(swayc_t *container) { 279swayc_t *destroy_container(swayc_t *container) {
280 if (!ASSERT_NONNULL(container)) {
281 return NULL;
282 }
265 while (container->children->length == 0 && container->type == C_CONTAINER) { 283 while (container->children->length == 0 && container->type == C_CONTAINER) {
266 sway_log(L_DEBUG, "Container: Destroying container '%p'", container); 284 sway_log(L_DEBUG, "Container: Destroying container '%p'", container);
267 swayc_t *parent = container->parent; 285 swayc_t *parent = container->parent;
@@ -272,8 +290,7 @@ swayc_t *destroy_container(swayc_t *container) {
272} 290}
273 291
274swayc_t *destroy_view(swayc_t *view) { 292swayc_t *destroy_view(swayc_t *view) {
275 if (view == NULL) { 293 if (!ASSERT_NONNULL(view)) {
276 sway_log(L_DEBUG, "Warning: NULL passed into destroy_view");
277 return NULL; 294 return NULL;
278 } 295 }
279 sway_log(L_DEBUG, "Destroying view '%p'", view); 296 sway_log(L_DEBUG, "Destroying view '%p'", view);
@@ -287,6 +304,34 @@ swayc_t *destroy_view(swayc_t *view) {
287 return parent; 304 return parent;
288} 305}
289 306
307// Container lookup
308
309swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
310 if (!ASSERT_NONNULL(container)) {
311 return NULL;
312 }
313 if (!sway_assert(type < C_TYPES && type >= C_ROOT, "%s: invalid type", __func__)) {
314 return NULL;
315 }
316 do {
317 container = container->parent;
318 } while(container && container->type != type);
319 return container;
320}
321
322swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts layout) {
323 if (!ASSERT_NONNULL(container)) {
324 return NULL;
325 }
326 if (!sway_assert(layout < L_LAYOUTS && layout >= L_NONE, "%s: invalid layout", __func__)) {
327 return NULL;
328 }
329 do {
330 container = container->parent;
331 } while (container && container->layout != layout);
332 return container;
333}
334
290swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { 335swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) {
291 if (!container->children) { 336 if (!container->children) {
292 return NULL; 337 return NULL;
@@ -316,25 +361,27 @@ swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *da
316} 361}
317 362
318void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { 363void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
319 if (!container || !container->children || !container->children->length) { 364 if (container && container->children && container->children->length) {
320 return; 365 int i;
321 } 366 for (i = 0; i < container->children->length; ++i) {
322 int i; 367 swayc_t *child = container->children->items[i];
323 for (i = 0; i < container->children->length; ++i) {
324 swayc_t *child = container->children->items[i];
325 f(child, data);
326 container_map(child, f, data);
327 }
328 if (container->type == C_WORKSPACE) {
329 for (i = 0; i < container->floating->length; ++i) {
330 swayc_t *child = container->floating->items[i];
331 f(child, data); 368 f(child, data);
332 container_map(child, f, data); 369 container_map(child, f, data);
333 } 370 }
371 if (container->type == C_WORKSPACE) {
372 for (i = 0; i < container->floating->length; ++i) {
373 swayc_t *child = container->floating->items[i];
374 f(child, data);
375 container_map(child, f, data);
376 }
377 }
334 } 378 }
335} 379}
336 380
337void set_view_visibility(swayc_t *view, void *data) { 381void set_view_visibility(swayc_t *view, void *data) {
382 if (!ASSERT_NONNULL(view)) {
383 return;
384 }
338 uint32_t *p = data; 385 uint32_t *p = data;
339 if (view->type == C_VIEW) { 386 if (view->type == C_VIEW) {
340 wlc_view_set_mask(view->handle, *p); 387 wlc_view_set_mask(view->handle, *p);
@@ -348,6 +395,9 @@ void set_view_visibility(swayc_t *view, void *data) {
348} 395}
349 396
350void reset_gaps(swayc_t *view, void *data) { 397void reset_gaps(swayc_t *view, void *data) {
398 if (!ASSERT_NONNULL(view)) {
399 return;
400 }
351 if (view->type == C_OUTPUT) { 401 if (view->type == C_OUTPUT) {
352 view->gaps = config->gaps_outer; 402 view->gaps = config->gaps_outer;
353 } 403 }
diff --git a/sway/handlers.c b/sway/handlers.c
index 571dd2a6..53eae439 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -21,10 +21,7 @@ static struct wlc_origin mouse_origin;
21static bool pointer_test(swayc_t *view, void *_origin) { 21static bool pointer_test(swayc_t *view, void *_origin) {
22 const struct wlc_origin *origin = _origin; 22 const struct wlc_origin *origin = _origin;
23 // Determine the output that the view is under 23 // Determine the output that the view is under
24 swayc_t *parent = view; 24 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
25 while (parent->type != C_OUTPUT) {
26 parent = parent->parent;
27 }
28 if (origin->x >= view->x && origin->y >= view->y 25 if (origin->x >= view->x && origin->y >= view->y
29 && origin->x < view->x + view->width && origin->y < view->y + view->height 26 && origin->x < view->x + view->width && origin->y < view->y + view->height
30 && view->visible && parent == root_container.focused) { 27 && view->visible && parent == root_container.focused) {
@@ -192,10 +189,7 @@ static bool handle_view_created(wlc_handle handle) {
192 189
193 if (newview) { 190 if (newview) {
194 set_focused_container(newview); 191 set_focused_container(newview);
195 swayc_t *output = newview->parent; 192 swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT);
196 while (output && output->type != C_OUTPUT) {
197 output = output->parent;
198 }
199 arrange_windows(output, -1, -1); 193 arrange_windows(output, -1, -1);
200 } 194 }
201 return true; 195 return true;
@@ -263,10 +257,7 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
263 arrange_windows(c->parent, -1, -1); 257 arrange_windows(c->parent, -1, -1);
264 // Set it as focused window for that workspace if its going fullscreen 258 // Set it as focused window for that workspace if its going fullscreen
265 if (toggle) { 259 if (toggle) {
266 swayc_t *ws = c; 260 swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE);
267 while (ws->type != C_WORKSPACE) {
268 ws = ws->parent;
269 }
270 // Set ws focus to c 261 // Set ws focus to c
271 set_focused_container_for(ws, c); 262 set_focused_container_for(ws, c);
272 } 263 }
diff --git a/sway/input_state.c b/sway/input_state.c
index e592cfc1..ef5d6df0 100644
--- a/sway/input_state.c
+++ b/sway/input_state.c
@@ -8,6 +8,13 @@
8 8
9static keycode key_state_array[KEY_STATE_MAX_LENGTH]; 9static keycode key_state_array[KEY_STATE_MAX_LENGTH];
10 10
11void input_init(void) {
12 int i;
13 for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) {
14 key_state_array[i] = 0;
15 }
16}
17
11static uint8_t find_key(keycode key) { 18static uint8_t find_key(keycode key) {
12 int i; 19 int i;
13 for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) { 20 for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) {
diff --git a/sway/ipc.c b/sway/ipc.c
index 505c17f8..39e580cd 100644
--- a/sway/ipc.c
+++ b/sway/ipc.c
@@ -11,10 +11,13 @@
11#include <stropts.h> 11#include <stropts.h>
12#include <sys/ioctl.h> 12#include <sys/ioctl.h>
13#include <fcntl.h> 13#include <fcntl.h>
14#include <ctype.h>
14#include "ipc.h" 15#include "ipc.h"
15#include "log.h" 16#include "log.h"
16#include "config.h" 17#include "config.h"
17#include "commands.h" 18#include "commands.h"
19#include "list.h"
20#include "stringop.h"
18 21
19static int ipc_socket = -1; 22static int ipc_socket = -1;
20static struct wlc_event_source *ipc_event_source = NULL; 23static struct wlc_event_source *ipc_event_source = NULL;
@@ -37,6 +40,10 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
37void ipc_client_disconnect(struct ipc_client *client); 40void ipc_client_disconnect(struct ipc_client *client);
38void ipc_client_handle_command(struct ipc_client *client); 41void ipc_client_handle_command(struct ipc_client *client);
39bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); 42bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
43void ipc_get_workspaces_callback(swayc_t *container, void *data);
44void ipc_get_outputs_callback(swayc_t *container, void *data);
45
46char *json_list(list_t *items);
40 47
41void ipc_init(void) { 48void ipc_init(void) {
42 ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); 49 ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
@@ -195,6 +202,26 @@ void ipc_client_handle_command(struct ipc_client *client) {
195 ipc_send_reply(client, reply, (uint32_t) length); 202 ipc_send_reply(client, reply, (uint32_t) length);
196 break; 203 break;
197 } 204 }
205 case IPC_GET_WORKSPACES:
206 {
207 list_t *workspaces = create_list();
208 container_map(&root_container, ipc_get_workspaces_callback, workspaces);
209 char *json = json_list(workspaces);
210 free_flat_list(workspaces);
211 ipc_send_reply(client, json, strlen(json));
212 free(json);
213 break;
214 }
215 case IPC_GET_OUTPUTS:
216 {
217 list_t *outputs = create_list();
218 container_map(&root_container, ipc_get_outputs_callback, outputs);
219 char *json = json_list(outputs);
220 free_flat_list(outputs);
221 ipc_send_reply(client, json, strlen(json));
222 free(json);
223 break;
224 }
198 default: 225 default:
199 sway_log(L_INFO, "Unknown IPC command type %i", client->current_command); 226 sway_log(L_INFO, "Unknown IPC command type %i", client->current_command);
200 ipc_client_disconnect(client); 227 ipc_client_disconnect(client);
@@ -227,3 +254,68 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
227 254
228 return true; 255 return true;
229} 256}
257
258char *json_list(list_t *items) {
259 char *json_elements = join_list(items, ",");
260 size_t len = strlen(json_elements);
261 char *json = malloc(len + 3);
262 json[0] = '[';
263 memcpy(json + 1, json_elements, len);
264 json[len+1] = ']';
265 json[len+2] = '\0';
266 free(json_elements);
267 return json;
268}
269
270void ipc_get_workspaces_callback(swayc_t *container, void *data) {
271 if (container->type == C_WORKSPACE) {
272 char *json = malloc(512); // Output should usually be around 180 chars
273 int num = isdigit(container->name[0]) ? atoi(container->name) : -1;
274 // TODO: escape the name (quotation marks, unicode)
275 sprintf(json,
276 "{"
277 "\"num\":%d,"
278 "\"name\":\"%s\","
279 "\"visible\":%s,"
280 "\"focused\":%s,"
281 "\"rect\":{"
282 "\"x\":%d,"
283 "\"y\":%d,"
284 "\"width\":%d,"
285 "\"height\":%d"
286 "},"
287 "\"output\":\"%s\","
288 "\"urgent\":%s"
289 "}",
290 num, container->name, container->visible ? "true" : "false", container->is_focused ? "true" : "false",
291 container->x, container->y, container->width, container->height,
292 container->parent->name, "false" // TODO: urgent hint
293 );
294 list_add((list_t *)data, json);
295 }
296}
297
298void ipc_get_outputs_callback(swayc_t *container, void *data) {
299 if (container->type == C_OUTPUT) {
300 char *json = malloc(512); // Output should usually be around 130 chars
301 // TODO: escape the name (quotation marks, unicode)
302 sprintf(json,
303 "{"
304 "\"name\":\"%s\","
305 "\"active\":%s,"
306 "\"primary\":%s,"
307 "\"rect\":{"
308 "\"x\":%d,"
309 "\"y\":%d,"
310 "\"width\":%d,"
311 "\"height\":%d"
312 "},"
313 "\"current_workspace\":\"%s\""
314 "}",
315 container->name, "true", "false", // TODO: active, primary
316 container->x, container->y, container->width, container->height,
317 container->focused ? container->focused->name : ""
318 );
319 list_add((list_t *)data, json);
320 }
321}
diff --git a/sway/layout.c b/sway/layout.c
index 12b27987..35aa4942 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -161,10 +161,7 @@ void arrange_windows(swayc_t *container, double width, double height) {
161 } 161 }
162 }; 162 };
163 if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { 163 if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
164 swayc_t *parent = container; 164 swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
165 while (parent->type != C_OUTPUT) {
166 parent = parent->parent;
167 }
168 geometry.origin.x = 0; 165 geometry.origin.x = 0;
169 geometry.origin.y = 0; 166 geometry.origin.y = 0;
170 geometry.size.w = parent->width; 167 geometry.size.w = parent->width;
@@ -263,10 +260,7 @@ void arrange_windows(swayc_t *container, double width, double height) {
263 } 260 }
264 }; 261 };
265 if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { 262 if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) {
266 swayc_t *parent = view; 263 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
267 while (parent->type != C_OUTPUT) {
268 parent = parent->parent;
269 }
270 geometry.origin.x = 0; 264 geometry.origin.x = 0;
271 geometry.origin.y = 0; 265 geometry.origin.y = 0;
272 geometry.size.w = parent->width; 266 geometry.size.w = parent->width;
diff --git a/sway/stringop.c b/sway/stringop.c
index 1dff97bf..c39e2c34 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -4,6 +4,7 @@
4#include "string.h" 4#include "string.h"
5#include "list.h" 5#include "list.h"
6#include <strings.h> 6#include <strings.h>
7#include <log.h>
7 8
8/* Note: This returns 8 characters for trimmed_start per tab character. */ 9/* Note: This returns 8 characters for trimmed_start per tab character. */
9char *strip_whitespace(char *_str, int *trimmed_start) { 10char *strip_whitespace(char *_str, int *trimmed_start) {
@@ -197,3 +198,41 @@ char *join_args(char **argv, int argc) {
197 res[len - 1] = '\0'; 198 res[len - 1] = '\0';
198 return res; 199 return res;
199} 200}
201
202/*
203 * Join a list of strings, adding separator in between. Separator can be NULL.
204 */
205char *join_list(list_t *list, char *separator) {
206 if (!sway_assert(list != NULL, "list != NULL") || list->length == 0) {
207 return NULL;
208 }
209
210 size_t len = 1; // NULL terminator
211 size_t sep_len = 0;
212 if (separator != NULL) {
213 sep_len = strlen(separator);
214 len += (list->length - 1) * sep_len;
215 }
216
217 for (int i = 0; i < list->length; i++) {
218 len += strlen(list->items[i]);
219 }
220
221 char *res = malloc(len);
222
223 char *p = res + strlen(list->items[0]);
224 strcpy(res, list->items[0]);
225
226 for (int i = 1; i < list->length; i++) {
227 if (sep_len) {
228 memcpy(p, separator, sep_len);
229 p += sep_len;
230 }
231 strcpy(p, list->items[i]);
232 p += strlen(list->items[i]);
233 }
234
235 *p = '\0';
236
237 return res;
238}
diff --git a/sway/workspace.c b/sway/workspace.c
index 0f44d3b0..d436da8e 100644
--- a/sway/workspace.c
+++ b/sway/workspace.c
@@ -75,9 +75,7 @@ char *workspace_next_name(void) {
75 75
76swayc_t *workspace_create(const char* name) { 76swayc_t *workspace_create(const char* name) {
77 swayc_t *parent = get_focused_container(&root_container); 77 swayc_t *parent = get_focused_container(&root_container);
78 while (parent->type != C_OUTPUT) { 78 parent = swayc_parent_by_type(parent, C_OUTPUT);
79 parent = parent->parent;
80 }
81 return new_workspace(parent, name); 79 return new_workspace(parent, name);
82} 80}
83 81