aboutsummaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar Half-Shot <half-shot@molrams.com>2015-08-20 21:32:08 +0100
committerLibravatar Half-Shot <half-shot@molrams.com>2015-08-20 21:32:08 +0100
commit5a9ba261bca4ca709ec7a14d2019b55d9ce06994 (patch)
treefe1a924cf8055b2b722566db6ab98295dcf08ce7 /sway
parentBasic left right move command implemented. (diff)
parentMerge pull request #104 from minus7/ipc-get-messages (diff)
downloadsway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.tar.gz
sway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.tar.zst
sway-5a9ba261bca4ca709ec7a14d2019b55d9ce06994.zip
Merge branch 'master' of https://github.com/SirCmpwn/sway
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c186
-rw-r--r--sway/config.c218
-rw-r--r--sway/container.c166
-rw-r--r--sway/focus.c87
-rw-r--r--sway/handlers.c326
-rw-r--r--sway/input_state.c68
-rw-r--r--sway/ipc.c321
-rw-r--r--sway/layout.c186
-rw-r--r--sway/log.c117
-rw-r--r--sway/main.c96
-rw-r--r--sway/readline.c12
-rw-r--r--sway/stringop.c39
-rw-r--r--sway/workspace.c77
13 files changed, 1356 insertions, 543 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 1ca5c17f..e39b781a 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -3,6 +3,7 @@
3#include <wlc/wlc.h> 3#include <wlc/wlc.h>
4#include <stdio.h> 4#include <stdio.h>
5#include <stdlib.h> 5#include <stdlib.h>
6#include <errno.h>
6#include <string.h> 7#include <string.h>
7#include <unistd.h> 8#include <unistd.h>
8#include <ctype.h> 9#include <ctype.h>
@@ -14,6 +15,7 @@
14#include "commands.h" 15#include "commands.h"
15#include "container.h" 16#include "container.h"
16#include "handlers.h" 17#include "handlers.h"
18#include "sway.h"
17 19
18struct modifier_key { 20struct modifier_key {
19 char *name; 21 char *name;
@@ -75,6 +77,18 @@ static bool checkarg(int argc, char *name, enum expected_args type, int val) {
75 return false; 77 return false;
76} 78}
77 79
80static int bindsym_sort(const void *_lbind, const void *_rbind) {
81 const struct sway_binding *lbind = *(void **)_lbind;
82 const struct sway_binding *rbind = *(void **)_rbind;
83 unsigned int lmod = 0, rmod = 0, i;
84
85 // Count how any modifiers are pressed
86 for (i = 0; i < 8 * sizeof(lbind->modifiers); ++i) {
87 lmod += lbind->modifiers & 1 << i;
88 rmod += rbind->modifiers & 1 << i;
89 }
90 return (rbind->keys->length + rmod) - (lbind->keys->length + lmod);
91}
78 92
79static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) { 93static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
80 if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)) { 94 if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)) {
@@ -104,6 +118,10 @@ static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
104 xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], XKB_KEYSYM_CASE_INSENSITIVE); 118 xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], XKB_KEYSYM_CASE_INSENSITIVE);
105 if (!sym) { 119 if (!sym) {
106 sway_log(L_ERROR, "bindsym - unknown key %s", (char *)split->items[i]); 120 sway_log(L_ERROR, "bindsym - unknown key %s", (char *)split->items[i]);
121 list_free(binding->keys);
122 free(binding->command);
123 free(binding);
124 list_free(split);
107 return false; 125 return false;
108 } 126 }
109 xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); 127 xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t));
@@ -113,7 +131,10 @@ static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
113 list_free(split); 131 list_free(split);
114 132
115 // TODO: Check if there are other commands with this key binding 133 // TODO: Check if there are other commands with this key binding
116 list_add(config->current_mode->bindings, binding); 134 struct sway_mode *mode = config->current_mode;
135 list_add(mode->bindings, binding);
136 qsort(mode->bindings->items, mode->bindings->length,
137 sizeof(mode->bindings->items[0]), bindsym_sort);
117 138
118 sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command); 139 sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command);
119 return true; 140 return true;
@@ -166,7 +187,7 @@ static bool cmd_exit(struct sway_config *config, int argc, char **argv) {
166 } 187 }
167 // Close all views 188 // Close all views
168 container_map(&root_container, kill_views, NULL); 189 container_map(&root_container, kill_views, NULL);
169 exit(0); 190 sway_terminate();
170 return true; 191 return true;
171} 192}
172 193
@@ -181,43 +202,28 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
181 if (view->type != C_VIEW) { 202 if (view->type != C_VIEW) {
182 return true; 203 return true;
183 } 204 }
184 int i;
185 // Change from nonfloating to floating 205 // Change from nonfloating to floating
186 if (!view->is_floating) { 206 if (!view->is_floating) {
187 view->is_floating = true; 207 // Remove view from its current location
188 for (i = 0; i < view->parent->children->length; i++) { 208 destroy_container(remove_child(view));
189 if (view->parent->children->items[i] == view) { 209
190 // Try to use desired geometry to set w/h 210 // and move it into workspace floating
191 if (view->desired_width != -1) { 211 add_floating(active_workspace,view);
192 view->width = view->desired_width; 212 view->x = (active_workspace->width - view->width)/2;
193 } 213 view->y = (active_workspace->height - view->height)/2;
194 if (view->desired_height != -1) { 214 if (view->desired_width != -1) {
195 view->height = view->desired_height; 215 view->width = view->desired_width;
196 } 216 }
197 217 if (view->desired_height != -1) {
198 // Swap from the list of whatever container the view was in 218 view->height = view->desired_height;
199 // to the workspace->floating list
200 list_del(view->parent->children, i);
201 list_add(active_workspace->floating, view);
202 destroy_container(view->parent);
203
204 // Set the new position of the container and arrange windows
205 view->x = (active_workspace->width - view->width)/2;
206 view->y = (active_workspace->height - view->height)/2;
207 sway_log(L_INFO, "Setting container %p to floating at coordinates X:%d Y:%d, W:%d, H:%d", view, view->x, view->y, view->width, view->height);
208 // Change parent to active_workspace
209 view->parent = active_workspace;
210 arrange_windows(active_workspace, -1, -1);
211 return true;
212 }
213 } 219 }
220 arrange_windows(active_workspace, -1, -1);
214 } else { 221 } else {
215 // Delete the view from the floating list and unset its is_floating flag 222 // Delete the view from the floating list and unset its is_floating flag
216 // Using length-1 as the index is safe because the view must be the currently 223 // Using length-1 as the index is safe because the view must be the currently
217 // focused floating output 224 // focused floating output
218 list_del(active_workspace->floating, active_workspace->floating->length - 1); 225 remove_child(view);
219 view->is_floating = false; 226 view->is_floating = false;
220 active_workspace->focused = NULL;
221 // Get the properly focused container, and add in the view there 227 // Get the properly focused container, and add in the view there
222 swayc_t *focused = container_under_pointer(); 228 swayc_t *focused = container_under_pointer();
223 // If focused is null, it's because the currently focused container is a workspace 229 // If focused is null, it's because the currently focused container is a workspace
@@ -228,21 +234,20 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
228 234
229 sway_log(L_DEBUG, "Non-floating focused container is %p", focused); 235 sway_log(L_DEBUG, "Non-floating focused container is %p", focused);
230 236
231 //Case of focused workspace, just create as child of it 237 // Case of focused workspace, just create as child of it
232 if (focused->type == C_WORKSPACE) { 238 if (focused->type == C_WORKSPACE) {
233 add_child(focused, view); 239 add_child(focused, view);
234 } 240 }
235 //Regular case, create as sibling of current container 241 // Regular case, create as sibling of current container
236 else { 242 else {
237 add_sibling(focused, view); 243 add_sibling(focused, view);
238 } 244 }
239 // Refocus on the view once its been put back into the layout 245 // Refocus on the view once its been put back into the layout
240 set_focused_container(view); 246 view->width = view->height = 0;
241 arrange_windows(active_workspace, -1, -1); 247 arrange_windows(active_workspace, -1, -1);
242 return true;
243 } 248 }
249 set_focused_container(view);
244 } 250 }
245
246 return true; 251 return true;
247} 252}
248 253
@@ -250,11 +255,29 @@ static bool cmd_floating_mod(struct sway_config *config, int argc, char **argv)
250 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) { 255 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) {
251 return false; 256 return false;
252 } 257 }
253 config->floating_mod = xkb_keysym_from_name(argv[0], XKB_KEYSYM_CASE_INSENSITIVE); 258 int i, j;
259 list_t *split = split_string(argv[0], "+");
260 config->floating_mod = 0;
261
262 // set modifer keys
263 for (i = 0; i < split->length; ++i) {
264 for (j = 0; j < sizeof(modifiers) / sizeof(struct modifier_key); ++j) {
265 if (strcasecmp(modifiers[j].name, split->items[i]) == 0) {
266 config->floating_mod |= modifiers[j].mod;
267 }
268 }
269 }
270 list_free(split);
271 if (!config->floating_mod) {
272 sway_log(L_ERROR, "bindsym - unknown keys %s", argv[0]);
273 return false;
274 }
254 return true; 275 return true;
255} 276}
256 277
257static bool cmd_focus(struct sway_config *config, int argc, char **argv) { 278static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
279 static int floating_toggled_index = 0;
280 static int tiled_toggled_index = 0;
258 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) { 281 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) {
259 return false; 282 return false;
260 } 283 }
@@ -268,7 +291,44 @@ static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
268 return move_focus(MOVE_DOWN); 291 return move_focus(MOVE_DOWN);
269 } else if (strcasecmp(argv[0], "parent") == 0) { 292 } else if (strcasecmp(argv[0], "parent") == 0) {
270 return move_focus(MOVE_PARENT); 293 return move_focus(MOVE_PARENT);
294 } else if (strcasecmp(argv[0], "mode_toggle") == 0) {
295 int i;
296 swayc_t *focused = get_focused_view(active_workspace);
297 if (focused->is_floating) {
298 if (active_workspace->children->length > 0) {
299 for (i = 0;i < active_workspace->floating->length; i++) {
300 if (active_workspace->floating->items[i] == focused) {
301 floating_toggled_index = i;
302 break;
303 }
304 }
305 if (active_workspace->children->length > tiled_toggled_index) {
306 set_focused_container(get_focused_view(active_workspace->children->items[tiled_toggled_index]));
307 } else {
308 set_focused_container(get_focused_view(active_workspace->children->items[0]));
309 tiled_toggled_index = 0;
310 }
311 }
312 } else {
313 if (active_workspace->floating->length > 0) {
314 for (i = 0;i < active_workspace->children->length; i++) {
315 if (active_workspace->children->items[i] == focused) {
316 tiled_toggled_index = i;
317 break;
318 }
319 }
320 if (active_workspace->floating->length > floating_toggled_index) {
321 swayc_t *floating = active_workspace->floating->items[floating_toggled_index];
322 set_focused_container(get_focused_view(floating));
323 } else {
324 swayc_t *floating = active_workspace->floating->items[active_workspace->floating->length - 1];
325 set_focused_container(get_focused_view(floating));
326 tiled_toggled_index = active_workspace->floating->length - 1;
327 }
328 }
329 }
271 } 330 }
331
272 return true; 332 return true;
273} 333}
274 334
@@ -303,6 +363,42 @@ static bool cmd_move(struct sway_config *config, int argc, char **argv) {
303 363
304 return true; 364 return true;
305 365
366static bool cmd_gaps(struct sway_config *config, int argc, char **argv) {
367 if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
368 return false;
369 }
370
371 if (argc == 1) {
372 char *end;
373 int amount = (int)strtol(argv[0], &end, 10);
374 if (errno == ERANGE || amount == 0) {
375 errno = 0;
376 return false;
377 }
378 if (config->gaps_inner == 0) {
379 config->gaps_inner = amount;
380 }
381 if (config->gaps_outer == 0) {
382 config->gaps_outer = amount;
383 }
384 } else if (argc == 2) {
385 char *end;
386 int amount = (int)strtol(argv[1], &end, 10);
387 if (errno == ERANGE || amount == 0) {
388 errno = 0;
389 return false;
390 }
391 if (strcasecmp(argv[0], "inner") == 0) {
392 config->gaps_inner = amount;
393 } else if (strcasecmp(argv[0], "outer") == 0) {
394 config->gaps_outer = amount;
395 } else {
396 return false;
397 }
398 } else {
399 return false;
400 }
401 return true;
306} 402}
307 403
308static bool cmd_kill(struct sway_config *config, int argc, char **argv) { 404static bool cmd_kill(struct sway_config *config, int argc, char **argv) {
@@ -316,7 +412,6 @@ static bool cmd_layout(struct sway_config *config, int argc, char **argv) {
316 return false; 412 return false;
317 } 413 }
318 swayc_t *parent = get_focused_container(&root_container); 414 swayc_t *parent = get_focused_container(&root_container);
319
320 while (parent->type == C_VIEW) { 415 while (parent->type == C_VIEW) {
321 parent = parent->parent; 416 parent = parent->parent;
322 } 417 }
@@ -341,7 +436,7 @@ static bool cmd_reload(struct sway_config *config, int argc, char **argv) {
341 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) { 436 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) {
342 return false; 437 return false;
343 } 438 }
344 if (!load_config()) { 439 if (!load_config(NULL)) { // TODO: Use config given from -c
345 return false; 440 return false;
346 } 441 }
347 arrange_windows(&root_container, -1, -1); 442 arrange_windows(&root_container, -1, -1);
@@ -435,14 +530,12 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) {
435 swayc_t *container = get_focused_view(&root_container); 530 swayc_t *container = get_focused_view(&root_container);
436 bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0; 531 bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0;
437 wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); 532 wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current);
438 //Resize workspace if going from fullscreen -> notfullscreen 533 // Resize workspace if going from fullscreen -> notfullscreen
439 //otherwise just resize container 534 // otherwise just resize container
440 if (current) { 535 if (current) {
441 while (container->type != C_WORKSPACE) { 536 container = swayc_parent_by_type(container, C_WORKSPACE);
442 container = container->parent;
443 }
444 } 537 }
445 //Only resize container when going into fullscreen 538 // Only resize container when going into fullscreen
446 arrange_windows(container, -1, -1); 539 arrange_windows(container, -1, -1);
447 540
448 return true; 541 return true;
@@ -508,6 +601,7 @@ static struct cmd_handler handlers[] = {
508 { "focus", cmd_focus }, 601 { "focus", cmd_focus },
509 { "focus_follows_mouse", cmd_focus_follows_mouse }, 602 { "focus_follows_mouse", cmd_focus_follows_mouse },
510 { "fullscreen", cmd_fullscreen }, 603 { "fullscreen", cmd_fullscreen },
604 { "gaps", cmd_gaps },
511 { "kill", cmd_kill }, 605 { "kill", cmd_kill },
512 { "layout", cmd_layout }, 606 { "layout", cmd_layout },
513 { "log_colors", cmd_log_colors }, 607 { "log_colors", cmd_log_colors },
@@ -606,7 +700,7 @@ bool handle_command(struct sway_config *config, char *exec) {
606 char **argv = split_directive(exec + strlen(handler->command), &argc); 700 char **argv = split_directive(exec + strlen(handler->command), &argc);
607 int i; 701 int i;
608 702
609 //Perform var subs on all parts of the command 703 // Perform var subs on all parts of the command
610 for (i = 0; i < argc; ++i) { 704 for (i = 0; i < argc; ++i) {
611 argv[i] = do_var_replacement(config, argv[i]); 705 argv[i] = do_var_replacement(config, argv[i]);
612 } 706 }
diff --git a/sway/config.c b/sway/config.c
index f1de6080..9f65e8a2 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -8,6 +8,7 @@
8#include "log.h" 8#include "log.h"
9#include "commands.h" 9#include "commands.h"
10#include "config.h" 10#include "config.h"
11#include "layout.h"
11 12
12struct sway_config *config; 13struct sway_config *config;
13 14
@@ -15,121 +16,143 @@ static bool exists(const char *path) {
15 return access(path, R_OK) != -1; 16 return access(path, R_OK) != -1;
16} 17}
17 18
18static char *get_config_path() { 19void config_defaults(struct sway_config *config) {
19 char *name = "/.sway/config"; 20 config->symbols = create_list();
20 const char *home = getenv("HOME"); 21 config->modes = create_list();
22 config->cmd_queue = create_list();
23 config->workspace_outputs = create_list();
24 config->current_mode = malloc(sizeof(struct sway_mode));
25 config->current_mode->name = NULL;
26 config->current_mode->bindings = create_list();
27 list_add(config->modes, config->current_mode);
28 // Flags
29 config->focus_follows_mouse = true;
30 config->mouse_warping = true;
31 config->reloading = false;
32 config->active = false;
33 config->failed = false;
34 config->gaps_inner = 0;
35 config->gaps_outer = 0;
36}
21 37
22 // Check home dir 38void free_mode(struct sway_mode *mode) {
23 sway_log(L_DEBUG, "Trying to find config in ~/.sway/config"); 39 free(mode->name);
24 char *temp = malloc(strlen(home) + strlen(name) + 1); 40 free_flat_list(mode->bindings);
25 strcpy(temp, home); 41}
26 strcat(temp, name);
27 if (exists(temp)) {
28 return temp;
29 }
30 42
31 // Check XDG_CONFIG_HOME with fallback to ~/.config/ 43void free_config(struct sway_config *config) {
32 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_HOME/sway/config"); 44 int i;
33 char *xdg_config_home = getenv("XDG_CONFIG_HOME"); 45 for (i = 0; i < config->modes->length; ++i) {
34 if (xdg_config_home == NULL) { 46 free_mode((struct sway_mode *)config->modes->items[i]);
35 sway_log(L_DEBUG, "Falling back to ~/.config/sway/config");
36 name = "/.config/sway/config";
37 temp = malloc(strlen(home) + strlen(name) + 1);
38 strcpy(temp, home);
39 strcat(temp, name);
40 } else {
41 name = "/sway/config";
42 temp = malloc(strlen(xdg_config_home) + strlen(name) + 1);
43 strcpy(xdg_config_home, home);
44 strcat(temp, name);
45 } 47 }
46 if (exists(temp)) { 48 free_flat_list(config->modes);
47 return temp; 49 for (i = 0; i < config->workspace_outputs->length; ++i) {
50 struct workspace_output *wso = config->workspace_outputs->items[i];
51 free(wso->output);
52 free(wso->workspace);
48 } 53 }
49 54 free_flat_list(config->workspace_outputs);
50 // Check /etc/ 55 free_flat_list(config->cmd_queue);
51 sway_log(L_DEBUG, "Trying to find config in /etc/sway/config"); 56 for (i = 0; i < config->symbols->length; ++i) {
52 strcpy(temp, "/etc/sway/config"); 57 struct sway_variable *sym = config->symbols->items[i];
53 if (exists(temp)) { 58 free(sym->name);
54 return temp; 59 free(sym->value);
55 } 60 }
61 free_flat_list(config->symbols);
62}
56 63
57 // Check XDG_CONFIG_DIRS 64static const char *search_paths[] = {
58 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS"); 65 "$home/.sway/config",
59 char *xdg_config_dirs = getenv("XDG_CONFIG_DIRS"); 66 "$config/sway/config",
60 if (xdg_config_dirs != NULL) { 67 "/etc/sway/config",
61 list_t *paths = split_string(xdg_config_dirs, ":"); 68 "$home/.i3/config",
62 name = "/sway/config"; 69 "$config/.i3/config",
63 int i; 70 "/etc/i3/config"
64 for (i = 0; i < paths->length; i++ ) { 71};
65 temp = malloc(strlen(paths->items[i]) + strlen(name) + 1);
66 strcpy(temp, paths->items[i]);
67 strcat(temp, name);
68 if (exists(temp)) {
69 free_flat_list(paths);
70 return temp;
71 }
72 }
73 free_flat_list(paths);
74 }
75 72
76 //Now fall back to i3 paths and try the same thing 73static char *get_config_path() {
77 name = "/.i3/config"; 74 char *home = getenv("HOME");
78 sway_log(L_DEBUG, "Trying to find config in ~/.i3/config"); 75 if (home) {
79 temp = malloc(strlen(home) + strlen(name) + 1); 76 home = strdup(getenv("HOME"));
80 strcpy(temp, home);
81 strcat(temp, name);
82 if (exists(temp)) {
83 return temp;
84 } 77 }
85 78 char *config = getenv("XDG_CONFIG_HOME");
86 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_HOME/i3/config"); 79 if (config) {
87 if (xdg_config_home == NULL) { 80 config = strdup(getenv("XDG_CONFIG_HOME"));
88 sway_log(L_DEBUG, "Falling back to ~/.config/i3/config"); 81 } else if (home) {
89 name = "/.config/i3/config"; 82 const char *def = "/.config";
90 temp = malloc(strlen(home) + strlen(name) + 1); 83 config = malloc(strlen(home) + strlen(def) + 1);
91 strcpy(temp, home); 84 strcpy(config, home);
92 strcat(temp, name); 85 strcat(config, def);
93 } else { 86 } else {
94 name = "/i3/config"; 87 home = strdup("");
95 temp = malloc(strlen(xdg_config_home) + strlen(name) + 1); 88 config = strdup("");
96 strcpy(xdg_config_home, home);
97 strcat(temp, name);
98 }
99 if (exists(temp)) {
100 return temp;
101 } 89 }
102 90
103 sway_log(L_DEBUG, "Trying to find config in /etc/i3/config"); 91 // Set up a temporary config for holding set variables
104 strcpy(temp, "/etc/i3/config"); 92 struct sway_config *temp_config = malloc(sizeof(struct sway_config));
105 if (exists(temp)) { 93 config_defaults(temp_config);
106 return temp; 94 const char *set_home = "set $home ";
95 char *_home = malloc(strlen(home) + strlen(set_home) + 1);
96 strcpy(_home, set_home);
97 strcat(_home, home);
98 handle_command(temp_config, _home);
99 free(_home);
100 const char *set_config = "set $config ";
101 char *_config = malloc(strlen(config) + strlen(set_config) + 1);
102 strcpy(_config, set_config);
103 strcat(_config, config);
104 handle_command(temp_config, _config);
105 free(_config);
106
107 char *test = NULL;
108 int i;
109 for (i = 0; i < sizeof(search_paths) / sizeof(char *); ++i) {
110 test = strdup(search_paths[i]);
111 test = do_var_replacement(temp_config, test);
112 sway_log(L_DEBUG, "Checking for config at %s", test);
113 if (exists(test)) {
114 goto _continue;
115 }
116 free(test);
117 test = NULL;
107 } 118 }
108 119
109 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS"); 120 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
121 char *xdg_config_dirs = getenv("XDG_CONFIG_DIRS");
110 if (xdg_config_dirs != NULL) { 122 if (xdg_config_dirs != NULL) {
111 list_t *paths = split_string(xdg_config_dirs, ":"); 123 list_t *paths = split_string(xdg_config_dirs, ":");
112 name = "/i3/config"; 124 char *name = "/sway/config";
113 int i; 125 int i;
114 for (i = 0; i < paths->length; i++ ) { 126 for (i = 0; i < paths->length; i++ ) {
115 temp = malloc(strlen(paths->items[i]) + strlen(name) + 1); 127 test = malloc(strlen(paths->items[i]) + strlen(name) + 1);
116 strcpy(temp, paths->items[i]); 128 strcpy(test, paths->items[i]);
117 strcat(temp, name); 129 strcat(test, name);
118 if (exists(temp)) { 130 if (exists(test)) {
119 free_flat_list(paths); 131 free_flat_list(paths);
120 return temp; 132 return test;
121 } 133 }
134 free(test);
135 test = NULL;
122 } 136 }
123 free_flat_list(paths); 137 free_flat_list(paths);
124 } 138 }
125 139
126 return NULL; 140_continue:
141 free_config(temp_config);
142 free(home);
143 free(config);
144 return test;
127} 145}
128 146
129bool load_config(void) { 147bool load_config(const char *file) {
130 sway_log(L_INFO, "Loading config"); 148 sway_log(L_INFO, "Loading config");
131 149
132 char *path = get_config_path(); 150 char *path;
151 if (file != NULL) {
152 path = strdup(file);
153 } else {
154 path = get_config_path();
155 }
133 156
134 if (path == NULL) { 157 if (path == NULL) {
135 sway_log(L_ERROR, "Unable to find a config file!"); 158 sway_log(L_ERROR, "Unable to find a config file!");
@@ -155,23 +178,6 @@ bool load_config(void) {
155 return config_load_success; 178 return config_load_success;
156} 179}
157 180
158void config_defaults(struct sway_config *config) {
159 config->symbols = create_list();
160 config->modes = create_list();
161 config->cmd_queue = create_list();
162 config->workspace_outputs = create_list();
163 config->current_mode = malloc(sizeof(struct sway_mode));
164 config->current_mode->name = NULL;
165 config->current_mode->bindings = create_list();
166 list_add(config->modes, config->current_mode);
167 // Flags
168 config->focus_follows_mouse = true;
169 config->mouse_warping = true;
170 config->reloading = false;
171 config->active = false;
172 config->failed = false;
173}
174
175bool read_config(FILE *file, bool is_active) { 181bool read_config(FILE *file, bool is_active) {
176 struct sway_config *temp_config = malloc(sizeof(struct sway_config)); 182 struct sway_config *temp_config = malloc(sizeof(struct sway_config));
177 config_defaults(temp_config); 183 config_defaults(temp_config);
@@ -188,8 +194,8 @@ bool read_config(FILE *file, bool is_active) {
188 while (!feof(file)) { 194 while (!feof(file)) {
189 int _; 195 int _;
190 char *line = read_line(file); 196 char *line = read_line(file);
191 line = strip_comments(line);
192 line = strip_whitespace(line, &_); 197 line = strip_whitespace(line, &_);
198 line = strip_comments(line);
193 if (!line[0]) { 199 if (!line[0]) {
194 goto _continue; 200 goto _continue;
195 } 201 }
@@ -225,6 +231,8 @@ _continue:
225 231
226 if (is_active) { 232 if (is_active) {
227 temp_config->reloading = false; 233 temp_config->reloading = false;
234 container_map(&root_container, reset_gaps, NULL);
235 arrange_windows(&root_container, -1, -1);
228 } 236 }
229 config = temp_config; 237 config = temp_config;
230 238
diff --git a/sway/container.c b/sway/container.c
index 62c5bda0..7ccc2e09 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -8,53 +8,57 @@
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));
14 c->handle = -1; 16 c->handle = -1;
15 c->layout = L_NONE; 17 c->layout = L_NONE;
16 c->type = type; 18 c->type = type;
17 c->weight = 1;
18 if (type != C_VIEW) { 19 if (type != C_VIEW) {
19 c->children = create_list(); 20 c->children = create_list();
20 } 21 }
21 return c; 22 return c;
22} 23}
23 24
24static void free_swayc(swayc_t *c) { 25static void free_swayc(swayc_t *cont) {
26 if (!ASSERT_NONNULL(cont)) {
27 return;
28 }
25 // TODO does not properly handle containers with children, 29 // TODO does not properly handle containers with children,
26 // TODO but functions that call this usually check for that 30 // TODO but functions that call this usually check for that
27 if (c->children) { 31 if (cont->children) {
28 if (c->children->length) { 32 if (cont->children->length) {
29 int i; 33 int i;
30 for (i = 0; i < c->children->length; ++i) { 34 for (i = 0; i < cont->children->length; ++i) {
31 free_swayc(c->children->items[i]); 35 free_swayc(cont->children->items[i]);
32 } 36 }
33 } 37 }
34 list_free(c->children); 38 list_free(cont->children);
35 } 39 }
36 if (c->floating) { 40 if (cont->floating) {
37 if (c->floating->length) { 41 if (cont->floating->length) {
38 int i; 42 int i;
39 for (i = 0; i < c->floating->length; ++i) { 43 for (i = 0; i < cont->floating->length; ++i) {
40 free_swayc(c->floating->items[i]); 44 free_swayc(cont->floating->items[i]);
41 } 45 }
42 } 46 }
43 list_free(c->floating); 47 list_free(cont->floating);
44 } 48 }
45 if (c->parent) { 49 if (cont->parent) {
46 remove_child(c); 50 remove_child(cont);
47 } 51 }
48 if (c->name) { 52 if (cont->name) {
49 free(c->name); 53 free(cont->name);
50 } 54 }
51 free(c); 55 free(cont);
52} 56}
53 57
54/* New containers */ 58// New containers
55 59
56static bool workspace_test(swayc_t *view, void *name) { 60static bool workspace_test(swayc_t *view, void *name) {
57 return strcasecmp(view->name, (char *)name); 61 return strcasecmp(view->name, (char *)name) == 0;
58} 62}
59 63
60swayc_t *new_output(wlc_handle handle) { 64swayc_t *new_output(wlc_handle handle) {
@@ -67,6 +71,7 @@ swayc_t *new_output(wlc_handle handle) {
67 output->height = size->h; 71 output->height = size->h;
68 output->handle = handle; 72 output->handle = handle;
69 output->name = name ? strdup(name) : NULL; 73 output->name = name ? strdup(name) : NULL;
74 output->gaps = config->gaps_outer + config->gaps_inner / 2;
70 75
71 add_child(&root_container, output); 76 add_child(&root_container, output);
72 77
@@ -80,8 +85,10 @@ swayc_t *new_output(wlc_handle handle) {
80 sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); 85 sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output);
81 // Check if any other workspaces are using this name 86 // Check if any other workspaces are using this name
82 if (find_container(&root_container, workspace_test, wso->workspace)) { 87 if (find_container(&root_container, workspace_test, wso->workspace)) {
88 sway_log(L_DEBUG, "But it's already taken");
83 break; 89 break;
84 } 90 }
91 sway_log(L_DEBUG, "So we're going to use it");
85 ws_name = strdup(wso->workspace); 92 ws_name = strdup(wso->workspace);
86 break; 93 break;
87 } 94 }
@@ -101,10 +108,15 @@ swayc_t *new_output(wlc_handle handle) {
101} 108}
102 109
103swayc_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 }
104 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);
105 swayc_t *workspace = new_swayc(C_WORKSPACE); 115 swayc_t *workspace = new_swayc(C_WORKSPACE);
106 116
107 workspace->layout = L_HORIZ; // TODO: default layout 117 workspace->layout = L_HORIZ; // TODO: default layout
118 workspace->x = output->x;
119 workspace->y = output->y;
108 workspace->width = output->width; 120 workspace->width = output->width;
109 workspace->height = output->height; 121 workspace->height = output->height;
110 workspace->name = strdup(name); 122 workspace->name = strdup(name);
@@ -116,6 +128,9 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
116} 128}
117 129
118swayc_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 }
119 swayc_t *cont = new_swayc(C_CONTAINER); 134 swayc_t *cont = new_swayc(C_CONTAINER);
120 135
121 sway_log(L_DEBUG, "creating container %p around %p", cont, child); 136 sway_log(L_DEBUG, "creating container %p around %p", cont, child);
@@ -147,6 +162,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
147 // give them proper layouts 162 // give them proper layouts
148 cont->layout = workspace->layout; 163 cont->layout = workspace->layout;
149 workspace->layout = layout; 164 workspace->layout = layout;
165 set_focused_container_for(workspace, get_focused_view(workspace));
150 } else { // Or is built around container 166 } else { // Or is built around container
151 swayc_t *parent = replace_child(child, cont); 167 swayc_t *parent = replace_child(child, cont);
152 if (parent) { 168 if (parent) {
@@ -157,6 +173,9 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
157} 173}
158 174
159swayc_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 }
160 const char *title = wlc_view_get_title(handle); 179 const char *title = wlc_view_get_title(handle);
161 swayc_t *view = new_swayc(C_VIEW); 180 swayc_t *view = new_swayc(C_VIEW);
162 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",
@@ -166,11 +185,15 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
166 view->name = title ? strdup(title) : NULL; 185 view->name = title ? strdup(title) : NULL;
167 view->visible = true; 186 view->visible = true;
168 view->is_focused = true; 187 view->is_focused = true;
188 // Setup geometry
189 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
190 view->width = 0;
191 view->height = 0;
192 view->desired_width = geometry->size.w;
193 view->desired_height = geometry->size.h;
169 194
170 view->desired_width = -1; 195 view->gaps = config->gaps_inner;
171 view->desired_height = -1;
172 196
173 // TODO: properly set this
174 view->is_floating = false; 197 view->is_floating = false;
175 198
176 if (sibling->type == C_WORKSPACE) { 199 if (sibling->type == C_WORKSPACE) {
@@ -196,8 +219,9 @@ swayc_t *new_floating_view(wlc_handle handle) {
196 // Set the geometry of the floating view 219 // Set the geometry of the floating view
197 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); 220 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle);
198 221
199 view->x = geometry->origin.x; 222 // give it requested geometry, but place in center
200 view->y = geometry->origin.y; 223 view->x = (active_workspace->width - geometry->size.w) / 2;
224 view->y = (active_workspace->height- geometry->size.h) / 2;
201 view->width = geometry->size.w; 225 view->width = geometry->size.w;
202 view->height = geometry->size.h; 226 view->height = geometry->size.h;
203 227
@@ -215,9 +239,12 @@ swayc_t *new_floating_view(wlc_handle handle) {
215 return view; 239 return view;
216} 240}
217 241
218/* Destroy container */ 242// Destroy container
219 243
220swayc_t *destroy_output(swayc_t *output) { 244swayc_t *destroy_output(swayc_t *output) {
245 if (!ASSERT_NONNULL(output)) {
246 return NULL;
247 }
221 if (output->children->length == 0) { 248 if (output->children->length == 0) {
222 // TODO move workspaces to other outputs 249 // TODO move workspaces to other outputs
223 } 250 }
@@ -227,23 +254,21 @@ swayc_t *destroy_output(swayc_t *output) {
227} 254}
228 255
229swayc_t *destroy_workspace(swayc_t *workspace) { 256swayc_t *destroy_workspace(swayc_t *workspace) {
257 if (!ASSERT_NONNULL(workspace)) {
258 return NULL;
259 }
230 // NOTE: This is called from elsewhere without checking children length 260 // NOTE: This is called from elsewhere without checking children length
231 // TODO move containers to other workspaces? 261 // TODO move containers to other workspaces?
232 // for now just dont delete 262 // for now just dont delete
233 263
234 // 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
235 swayc_t *output = workspace->parent; 265 swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
236 while (output && output->type != C_OUTPUT) { 266 if (output && output->children->length == 1) {
237 output = output->parent; 267 return NULL;
238 }
239 if (output) {
240 if (output->children->length == 1) {
241 return NULL;
242 }
243 } 268 }
244 269
245 if (workspace->children->length == 0) { 270 if (workspace->children->length == 0) {
246 sway_log(L_DEBUG, "Workspace: Destroying workspace '%s'", workspace->name); 271 sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name);
247 swayc_t *parent = workspace->parent; 272 swayc_t *parent = workspace->parent;
248 free_swayc(workspace); 273 free_swayc(workspace);
249 return parent; 274 return parent;
@@ -252,19 +277,20 @@ swayc_t *destroy_workspace(swayc_t *workspace) {
252} 277}
253 278
254swayc_t *destroy_container(swayc_t *container) { 279swayc_t *destroy_container(swayc_t *container) {
280 if (!ASSERT_NONNULL(container)) {
281 return NULL;
282 }
255 while (container->children->length == 0 && container->type == C_CONTAINER) { 283 while (container->children->length == 0 && container->type == C_CONTAINER) {
256 sway_log(L_DEBUG, "Container: Destroying container '%p'", container); 284 sway_log(L_DEBUG, "Container: Destroying container '%p'", container);
257 swayc_t *parent = container->parent; 285 swayc_t *parent = container->parent;
258 free_swayc(container); 286 free_swayc(container);
259
260 container = parent; 287 container = parent;
261 } 288 }
262 return container; 289 return container;
263} 290}
264 291
265swayc_t *destroy_view(swayc_t *view) { 292swayc_t *destroy_view(swayc_t *view) {
266 if (view == NULL) { 293 if (!ASSERT_NONNULL(view)) {
267 sway_log(L_DEBUG, "Warning: NULL passed into destroy_view");
268 return NULL; 294 return NULL;
269 } 295 }
270 sway_log(L_DEBUG, "Destroying view '%p'", view); 296 sway_log(L_DEBUG, "Destroying view '%p'", view);
@@ -278,6 +304,34 @@ swayc_t *destroy_view(swayc_t *view) {
278 return parent; 304 return parent;
279} 305}
280 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
281swayc_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) {
282 if (!container->children) { 336 if (!container->children) {
283 return NULL; 337 return NULL;
@@ -307,25 +361,27 @@ swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *da
307} 361}
308 362
309void 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) {
310 if (!container || !container->children || !container->children->length) { 364 if (container && container->children && container->children->length) {
311 return; 365 int i;
312 } 366 for (i = 0; i < container->children->length; ++i) {
313 int i; 367 swayc_t *child = container->children->items[i];
314 for (i = 0; i < container->children->length; ++i) {
315 swayc_t *child = container->children->items[i];
316 f(child, data);
317 container_map(child, f, data);
318 }
319 if (container->type == C_WORKSPACE) {
320 for (i = 0; i < container->floating->length; ++i) {
321 swayc_t *child = container->floating->items[i];
322 f(child, data); 368 f(child, data);
323 container_map(child, f, data); 369 container_map(child, f, data);
324 } 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 }
325 } 378 }
326} 379}
327 380
328void 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 }
329 uint32_t *p = data; 385 uint32_t *p = data;
330 if (view->type == C_VIEW) { 386 if (view->type == C_VIEW) {
331 wlc_view_set_mask(view->handle, *p); 387 wlc_view_set_mask(view->handle, *p);
@@ -337,3 +393,15 @@ void set_view_visibility(swayc_t *view, void *data) {
337 } 393 }
338 view->visible = (*p == 2); 394 view->visible = (*p == 2);
339} 395}
396
397void reset_gaps(swayc_t *view, void *data) {
398 if (!ASSERT_NONNULL(view)) {
399 return;
400 }
401 if (view->type == C_OUTPUT) {
402 view->gaps = config->gaps_outer;
403 }
404 if (view->type == C_VIEW) {
405 view->gaps = config->gaps_inner;
406 }
407}
diff --git a/sway/focus.c b/sway/focus.c
index 628316dd..5008dbbf 100644
--- a/sway/focus.c
+++ b/sway/focus.c
@@ -3,6 +3,7 @@
3#include "focus.h" 3#include "focus.h"
4#include "log.h" 4#include "log.h"
5#include "workspace.h" 5#include "workspace.h"
6#include "layout.h"
6 7
7bool locked_container_focus = false; 8bool locked_container_focus = false;
8bool locked_view_focus = false; 9bool locked_view_focus = false;
@@ -20,6 +21,8 @@ static void update_focus(swayc_t *c) {
20 // Case where output changes 21 // Case where output changes
21 case C_OUTPUT: 22 case C_OUTPUT:
22 wlc_output_focus(c->handle); 23 wlc_output_focus(c->handle);
24 // Set new workspace to the outputs focused workspace
25 active_workspace = c->focused;
23 break; 26 break;
24 27
25 // Case where workspace changes 28 // Case where workspace changes
@@ -51,74 +54,17 @@ static void update_focus(swayc_t *c) {
51} 54}
52 55
53bool move_focus(enum movement_direction direction) { 56bool move_focus(enum movement_direction direction) {
54 if (locked_container_focus) { 57 swayc_t *view = get_swayc_in_direction(
55 return false; 58 get_focused_container(&root_container), direction);
56 } 59 if (view) {
57 swayc_t *current = get_focused_container(&root_container); 60 if (direction == MOVE_PARENT) {
58 if (current->type == C_VIEW 61 set_focused_container(view);
59 && wlc_view_get_state(current->handle) & WLC_BIT_FULLSCREEN) {
60 return false;
61 }
62 swayc_t *parent = current->parent;
63
64 if (direction == MOVE_PARENT) {
65 if (parent->type == C_OUTPUT) {
66 sway_log(L_DEBUG, "Focus cannot move to parent");
67 return false;
68 } else { 62 } else {
69 sway_log(L_DEBUG, "Moving focus from %p:%ld to %p:%ld", 63 set_focused_container(get_focused_view(view));
70 current, current->handle, parent, parent->handle);
71 set_focused_container(parent);
72 return true;
73 }
74 }
75
76 while (true) {
77 sway_log(L_DEBUG, "Moving focus away from %p", current);
78
79 // Test if we can even make a difference here
80 bool can_move = false;
81 int diff = 0;
82 if (direction == MOVE_LEFT || direction == MOVE_RIGHT) {
83 if (parent->layout == L_HORIZ || parent->type == C_ROOT) {
84 can_move = true;
85 diff = direction == MOVE_LEFT ? -1 : 1;
86 }
87 } else {
88 if (parent->layout == L_VERT) {
89 can_move = true;
90 diff = direction == MOVE_UP ? -1 : 1;
91 }
92 }
93 sway_log(L_DEBUG, "Can move? %s", can_move ? "yes" : "no");
94 if (can_move) {
95 int i;
96 for (i = 0; i < parent->children->length; ++i) {
97 swayc_t *child = parent->children->items[i];
98 if (child == current) {
99 break;
100 }
101 }
102 int desired = i + diff;
103 sway_log(L_DEBUG, "Moving from %d to %d", i, desired);
104 if (desired < 0 || desired >= parent->children->length) {
105 can_move = false;
106 } else {
107 swayc_t *newview = parent->children->items[desired];
108 set_focused_container(get_focused_view(newview));
109 return true;
110 }
111 }
112 if (!can_move) {
113 sway_log(L_DEBUG, "Can't move at current level, moving up tree");
114 current = parent;
115 parent = parent->parent;
116 if (!parent) {
117 // Nothing we can do
118 return false;
119 }
120 } 64 }
65 return true;
121 } 66 }
67 return false;
122} 68}
123 69
124swayc_t *get_focused_container(swayc_t *parent) { 70swayc_t *get_focused_container(swayc_t *parent) {
@@ -142,13 +88,13 @@ void set_focused_container(swayc_t *c) {
142 // Find previous focused view, and the new focused view, if they are the same return 88 // Find previous focused view, and the new focused view, if they are the same return
143 swayc_t *focused = get_focused_view(&root_container); 89 swayc_t *focused = get_focused_view(&root_container);
144 swayc_t *workspace = active_workspace; 90 swayc_t *workspace = active_workspace;
145 if (focused == get_focused_view(c)) {
146 return;
147 }
148 91
149 // update container focus from here to root, making necessary changes along 92 // update container focus from here to root, making necessary changes along
150 // the way 93 // the way
151 swayc_t *p = c; 94 swayc_t *p = c;
95 if (p->type != C_OUTPUT && p->type != C_ROOT) {
96 p->is_focused = true;
97 }
152 while (p != &root_container) { 98 while (p != &root_container) {
153 update_focus(p); 99 update_focus(p);
154 p = p->parent; 100 p = p->parent;
@@ -171,8 +117,11 @@ void set_focused_container(swayc_t *c) {
171 } 117 }
172 // activate current focus 118 // activate current focus
173 if (p->type == C_VIEW) { 119 if (p->type == C_VIEW) {
174 wlc_view_focus(p->handle);
175 wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true); 120 wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true);
121 // set focus if view_focus is unlocked
122 if (!locked_view_focus) {
123 wlc_view_focus(p->handle);
124 }
176 } 125 }
177 } 126 }
178} 127}
diff --git a/sway/handlers.c b/sway/handlers.c
index 534b4e4f..79628fe5 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -13,21 +13,14 @@
13#include "workspace.h" 13#include "workspace.h"
14#include "container.h" 14#include "container.h"
15#include "focus.h" 15#include "focus.h"
16 16#include "input_state.h"
17uint32_t keys_pressed[32];
18 17
19static struct wlc_origin mouse_origin; 18static struct wlc_origin mouse_origin;
20 19
21static bool m1_held = false;
22static bool m2_held = false;
23
24static bool pointer_test(swayc_t *view, void *_origin) { 20static bool pointer_test(swayc_t *view, void *_origin) {
25 const struct wlc_origin *origin = _origin; 21 const struct wlc_origin *origin = _origin;
26 // Determine the output that the view is under 22 // Determine the output that the view is under
27 swayc_t *parent = view; 23 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
28 while (parent->type != C_OUTPUT) {
29 parent = parent->parent;
30 }
31 if (origin->x >= view->x && origin->y >= view->y 24 if (origin->x >= view->x && origin->y >= view->y
32 && origin->x < view->x + view->width && origin->y < view->y + view->height 25 && origin->x < view->x + view->width && origin->y < view->y + view->height
33 && view->visible && parent == root_container.focused) { 26 && view->visible && parent == root_container.focused) {
@@ -86,10 +79,12 @@ swayc_t *container_under_pointer(void) {
86 return lookup; 79 return lookup;
87} 80}
88 81
82/* Handles */
83
89static bool handle_output_created(wlc_handle output) { 84static bool handle_output_created(wlc_handle output) {
90 swayc_t *op = new_output(output); 85 swayc_t *op = new_output(output);
91 86
92 //Switch to workspace if we need to 87 // Switch to workspace if we need to
93 if (active_workspace == NULL) { 88 if (active_workspace == NULL) {
94 swayc_t *ws = op->children->items[0]; 89 swayc_t *ws = op->children->items[0];
95 workspace_switch(ws); 90 workspace_switch(ws);
@@ -111,7 +106,7 @@ static void handle_output_destroyed(wlc_handle output) {
111 if (list->length == 0) { 106 if (list->length == 0) {
112 active_workspace = NULL; 107 active_workspace = NULL;
113 } else { 108 } else {
114 //switch to other outputs active workspace 109 // switch to other outputs active workspace
115 workspace_switch(((swayc_t *)root_container.children->items[0])->focused); 110 workspace_switch(((swayc_t *)root_container.children->items[0])->focused);
116 } 111 }
117} 112}
@@ -137,38 +132,64 @@ static void handle_output_focused(wlc_handle output, bool focus) {
137} 132}
138 133
139static bool handle_view_created(wlc_handle handle) { 134static bool handle_view_created(wlc_handle handle) {
140 swayc_t *focused = get_focused_container(&root_container); 135 // if view is child of another view, the use that as focused container
136 wlc_handle parent = wlc_view_get_parent(handle);
137 swayc_t *focused = NULL;
141 swayc_t *newview = NULL; 138 swayc_t *newview = NULL;
139
140 // Get parent container, to add view in
141 if (parent) {
142 focused = get_swayc_for_handle(parent, &root_container);
143 }
144 if (!focused || focused->type == C_OUTPUT) {
145 focused = get_focused_container(&root_container);
146 }
147 sway_log(L_DEBUG, "handle:%ld type:%x state:%x parent:%ld "
148 "mask:%d (x:%d y:%d w:%d h:%d) title:%s "
149 "class:%s appid:%s",
150 handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent,
151 wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x,
152 wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w,
153 wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle),
154 wlc_view_get_class(handle), wlc_view_get_app_id(handle));
155
156 // TODO properly figure out how each window should be handled.
142 switch (wlc_view_get_type(handle)) { 157 switch (wlc_view_get_type(handle)) {
143 // regular view created regularly 158 // regular view created regularly
144 case 0: 159 case 0:
145 newview = new_view(focused, handle); 160 newview = new_view(focused, handle);
146 wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); 161 wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true);
147 break; 162 break;
148 // takes keyboard focus 163
164 // Dmenu keeps viewfocus, but others with this flag dont, for now simulate
165 // dmenu
149 case WLC_BIT_OVERRIDE_REDIRECT: 166 case WLC_BIT_OVERRIDE_REDIRECT:
150 sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT", handle); 167// locked_view_focus = true;
151 locked_view_focus = true;
152 wlc_view_focus(handle); 168 wlc_view_focus(handle);
153 wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); 169 wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true);
154 wlc_view_bring_to_front(handle); 170 wlc_view_bring_to_front(handle);
155 break; 171 break;
156 // Takes container focus 172
173 // Firefox popups have this flag set.
157 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: 174 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
158 sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT|WLC_BIT_MANAGED", handle);
159 wlc_view_bring_to_front(handle); 175 wlc_view_bring_to_front(handle);
160 locked_container_focus = true; 176 locked_container_focus = true;
161 break; 177 break;
162 // set modals as floating containers 178
179 // Modals, get focus, popups do not
163 case WLC_BIT_MODAL: 180 case WLC_BIT_MODAL:
181 wlc_view_focus(handle);
164 wlc_view_bring_to_front(handle); 182 wlc_view_bring_to_front(handle);
165 newview = new_floating_view(handle); 183 newview = new_floating_view(handle);
166 case WLC_BIT_POPUP: 184 case WLC_BIT_POPUP:
185 wlc_view_bring_to_front(handle);
167 break; 186 break;
168 } 187 }
188
169 if (newview) { 189 if (newview) {
170 set_focused_container(newview); 190 set_focused_container(newview);
171 arrange_windows(newview->parent, -1, -1); 191 swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT);
192 arrange_windows(output, -1, -1);
172 } 193 }
173 return true; 194 return true;
174} 195}
@@ -181,19 +202,19 @@ static void handle_view_destroyed(wlc_handle handle) {
181 // regular view created regularly 202 // regular view created regularly
182 case 0: 203 case 0:
183 case WLC_BIT_MODAL: 204 case WLC_BIT_MODAL:
205 case WLC_BIT_POPUP:
184 if (view) { 206 if (view) {
185 swayc_t *parent = destroy_view(view); 207 swayc_t *parent = destroy_view(view);
186 arrange_windows(parent, -1, -1); 208 arrange_windows(parent, -1, -1);
187 } 209 }
188 break; 210 break;
189 // takes keyboard focus 211 // DMENU has this flag, and takes view_focus, but other things with this
212 // flag dont
190 case WLC_BIT_OVERRIDE_REDIRECT: 213 case WLC_BIT_OVERRIDE_REDIRECT:
191 locked_view_focus = false; 214// locked_view_focus = false;
192 break; 215 break;
193 // Takes container focus
194 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: 216 case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
195 locked_container_focus = false; 217 locked_container_focus = false;
196 case WLC_BIT_POPUP:
197 break; 218 break;
198 } 219 }
199 set_focused_container(get_focused_view(&root_container)); 220 set_focused_container(get_focused_view(&root_container));
@@ -205,7 +226,7 @@ static void handle_view_focus(wlc_handle view, bool focus) {
205 226
206static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) { 227static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) {
207 sway_log(L_DEBUG, "geometry request %d x %d : %d x %d", 228 sway_log(L_DEBUG, "geometry request %d x %d : %d x %d",
208 geometry->origin.x, geometry->origin.y, geometry->size.w,geometry->size.h); 229 geometry->origin.x, geometry->origin.y, geometry->size.w, geometry->size.h);
209 // If the view is floating, then apply the geometry. 230 // If the view is floating, then apply the geometry.
210 // Otherwise save the desired width/height for the view. 231 // Otherwise save the desired width/height for the view.
211 // This will not do anything for the time being as WLC improperly sends geometry requests 232 // This will not do anything for the time being as WLC improperly sends geometry requests
@@ -225,21 +246,17 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo
225} 246}
226 247
227static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { 248static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) {
228 swayc_t *c = NULL; 249 swayc_t *c = get_swayc_for_handle(view, &root_container);
229 switch(state) { 250 switch (state) {
230 case WLC_BIT_FULLSCREEN: 251 case WLC_BIT_FULLSCREEN:
231 // i3 just lets it become fullscreen 252 // i3 just lets it become fullscreen
232 wlc_view_set_state(view, state, toggle); 253 wlc_view_set_state(view, state, toggle);
233 c = get_swayc_for_handle(view, &root_container);
234 sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d",view,c->name,toggle);
235 if (c) { 254 if (c) {
255 sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d", view, c->name, toggle);
236 arrange_windows(c->parent, -1, -1); 256 arrange_windows(c->parent, -1, -1);
237 // Set it as focused window for that workspace if its going fullscreen 257 // Set it as focused window for that workspace if its going fullscreen
238 if (toggle) { 258 if (toggle) {
239 swayc_t *ws = c; 259 swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE);
240 while (ws->type != C_WORKSPACE) {
241 ws = ws->parent;
242 }
243 // Set ws focus to c 260 // Set ws focus to c
244 set_focused_container_for(ws, c); 261 set_focused_container_for(ws, c);
245 } 262 }
@@ -248,7 +265,9 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
248 case WLC_BIT_MAXIMIZED: 265 case WLC_BIT_MAXIMIZED:
249 case WLC_BIT_RESIZING: 266 case WLC_BIT_RESIZING:
250 case WLC_BIT_MOVING: 267 case WLC_BIT_MOVING:
268 break;
251 case WLC_BIT_ACTIVATED: 269 case WLC_BIT_ACTIVATED:
270 sway_log(L_DEBUG, "View %p requested to be activated", c);
252 break; 271 break;
253 } 272 }
254 return; 273 return;
@@ -257,29 +276,38 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
257 276
258static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, 277static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
259 uint32_t key, uint32_t sym, enum wlc_key_state state) { 278 uint32_t key, uint32_t sym, enum wlc_key_state state) {
260 enum { QSIZE = 32 }; 279
261 if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) { 280 if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) {
262 return false; 281 return false;
263 } 282 }
264 static uint8_t head = 0; 283
265 bool cmd_success = false; 284 // Revert floating container back to original position on keypress
285 if (state == WLC_KEY_STATE_PRESSED &&
286 (pointer_state.floating.drag || pointer_state.floating.resize)) {
287 reset_floating(get_focused_view(&root_container));
288 }
266 289
267 struct sway_mode *mode = config->current_mode; 290 struct sway_mode *mode = config->current_mode;
291
292 if (sym < 70000 /* bullshit made up number */) {
293 if (!isalnum(sym) && sym != ' ' && sym != XKB_KEY_Escape && sym != XKB_KEY_Tab) {
294 // God fucking dammit
295 return false;
296 }
297 }
298
268 // Lowercase if necessary 299 // Lowercase if necessary
269 sym = tolower(sym); 300 sym = tolower(sym);
270 301
271 // Find key, if it has been pressed 302 int i;
272 int mid = 0; 303
273 while (mid < head && keys_pressed[mid] != sym) { 304 if (state == WLC_KEY_STATE_PRESSED) {
274 ++mid; 305 press_key(sym);
275 } 306 } else { // WLC_KEY_STATE_RELEASED
276 if (state == WLC_KEY_STATE_PRESSED && mid == head && head + 1 < QSIZE) { 307 release_key(sym);
277 keys_pressed[head++] = sym;
278 } else if (state == WLC_KEY_STATE_RELEASED && mid < head) {
279 memmove(keys_pressed + mid, keys_pressed + mid + 1, sizeof*keys_pressed * (--head - mid));
280 } 308 }
309
281 // TODO: reminder to check conflicts with mod+q+a versus mod+q 310 // TODO: reminder to check conflicts with mod+q+a versus mod+q
282 int i;
283 for (i = 0; i < mode->bindings->length; ++i) { 311 for (i = 0; i < mode->bindings->length; ++i) {
284 struct sway_binding *binding = mode->bindings->items[i]; 312 struct sway_binding *binding = mode->bindings->items[i];
285 313
@@ -287,39 +315,22 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
287 bool match; 315 bool match;
288 int j; 316 int j;
289 for (j = 0; j < binding->keys->length; ++j) { 317 for (j = 0; j < binding->keys->length; ++j) {
290 match = false;
291 xkb_keysym_t *key = binding->keys->items[j]; 318 xkb_keysym_t *key = binding->keys->items[j];
292 uint8_t k; 319 if ((match = check_key(*key)) == false) {
293 for (k = 0; k < head; ++k) {
294 if (keys_pressed[k] == *key) {
295 match = true;
296 break;
297 }
298 }
299 if (match == false) {
300 break; 320 break;
301 } 321 }
302 } 322 }
303
304 if (match) { 323 if (match) {
305 // Remove matched keys from keys_pressed
306 int j;
307 for (j = 0; j < binding->keys->length; ++j) {
308 uint8_t k;
309 for (k = 0; k < head; ++k) {
310 memmove(keys_pressed + k, keys_pressed + k + 1, sizeof*keys_pressed * (--head - k));
311 break;
312 }
313 }
314 if (state == WLC_KEY_STATE_PRESSED) { 324 if (state == WLC_KEY_STATE_PRESSED) {
315 cmd_success = handle_command(config, binding->command); 325 handle_command(config, binding->command);
326 return true;
316 } else if (state == WLC_KEY_STATE_RELEASED) { 327 } else if (state == WLC_KEY_STATE_RELEASED) {
317 // TODO: --released 328 // TODO: --released
318 } 329 }
319 } 330 }
320 } 331 }
321 } 332 }
322 return cmd_success; 333 return false;
323} 334}
324 335
325static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) { 336static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) {
@@ -327,119 +338,129 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
327 static wlc_handle prev_handle = 0; 338 static wlc_handle prev_handle = 0;
328 mouse_origin = *origin; 339 mouse_origin = *origin;
329 bool changed_floating = false; 340 bool changed_floating = false;
330 int i = 0;
331 if (!active_workspace) { 341 if (!active_workspace) {
332 return false; 342 return false;
333 } 343 }
334 // Do checks to determine if proper keys are being held 344 // Do checks to determine if proper keys are being held
335 swayc_t *view = active_workspace->focused; 345 swayc_t *view = get_focused_view(active_workspace);
336 if (m1_held && view) { 346 uint32_t edge = 0;
347 if (pointer_state.floating.drag && view) {
337 if (view->is_floating) { 348 if (view->is_floating) {
338 while (keys_pressed[i++]) { 349 int dx = mouse_origin.x - prev_pos.x;
339 if (keys_pressed[i] == config->floating_mod) { 350 int dy = mouse_origin.y - prev_pos.y;
340 int dx = mouse_origin.x - prev_pos.x; 351 view->x += dx;
341 int dy = mouse_origin.y - prev_pos.y; 352 view->y += dy;
342 sway_log(L_DEBUG, "Moving from px: %d to cx: %d and from py: %d to cy: %d", prev_pos.x, mouse_origin.x, prev_pos.y, mouse_origin.y); 353 changed_floating = true;
343 sway_log(L_DEBUG, "Moving: dx: %d, dy: %d", dx, dy);
344
345 view->x += dx;
346 view->y += dy;
347 changed_floating = true;
348 break;
349 }
350 }
351 } 354 }
352 } else if (m2_held && view) { 355 } else if (pointer_state.floating.resize && view) {
353 if (view->is_floating) { 356 if (view->is_floating) {
354 while (keys_pressed[i++]) { 357 int dx = mouse_origin.x - prev_pos.x;
355 if (keys_pressed[i] == config->floating_mod) { 358 int dy = mouse_origin.y - prev_pos.y;
356 int dx = mouse_origin.x - prev_pos.x; 359 int min_sane_w = 100;
357 int dy = mouse_origin.y - prev_pos.y; 360 int min_sane_h = 60;
358 sway_log(L_DEBUG, "Moving from px: %d to cx: %d and from py: %d to cy: %d", prev_pos.x, mouse_origin.x, prev_pos.y, mouse_origin.y); 361
359 sway_log(L_INFO, "Moving: dx: %d, dy: %d", dx, dy); 362 // Move and resize the view based on the dx/dy and mouse position
360 363 int midway_x = view->x + view->width/2;
361 // Move and resize the view based on the dx/dy and mouse position 364 int midway_y = view->y + view->height/2;
362 int midway_x = view->x + view->width/2; 365 if (dx < 0) {
363 int midway_y = view->y + view->height/2; 366 if (!pointer_state.lock.right) {
364 367 if (view->width > min_sane_w) {
365 if (dx < 0) {
366 changed_floating = true; 368 changed_floating = true;
367 if (mouse_origin.x > midway_x) { 369 view->width += dx;
368 sway_log(L_INFO, "Downsizing view to the left"); 370 edge += WLC_RESIZE_EDGE_RIGHT;
369 view->width += dx; 371 }
370 } else { 372 } else if (mouse_origin.x < midway_x && !pointer_state.lock.left) {
371 sway_log(L_INFO, "Upsizing view to the left"); 373 changed_floating = true;
372 view->x += dx; 374 view->x += dx;
373 view->width -= dx; 375 view->width -= dx;
374 } 376 edge += WLC_RESIZE_EDGE_LEFT;
375 } else if (dx > 0){ 377 }
378 } else if (dx > 0) {
379 if (mouse_origin.x > midway_x && !pointer_state.lock.right) {
380 changed_floating = true;
381 view->width += dx;
382 edge += WLC_RESIZE_EDGE_RIGHT;
383 } else if (!pointer_state.lock.left) {
384 if (view->width > min_sane_w) {
376 changed_floating = true; 385 changed_floating = true;
377 if (mouse_origin.x > midway_x) { 386 view->x += dx;
378 sway_log(L_INFO, "Upsizing to the right"); 387 view->width -= dx;
379 view->width += dx; 388 edge += WLC_RESIZE_EDGE_LEFT;
380 } else {
381 sway_log(L_INFO, "Downsizing to the right");
382 view->x += dx;
383 view->width -= dx;
384 }
385 } 389 }
390 }
391 }
386 392
387 if (dy < 0) { 393 if (dy < 0) {
394 if (!pointer_state.lock.bottom) {
395 if (view->height > min_sane_h) {
388 changed_floating = true; 396 changed_floating = true;
389 if (mouse_origin.y > midway_y) { 397 view->height += dy;
390 sway_log(L_INFO, "Downsizing view to the top"); 398 edge += WLC_RESIZE_EDGE_BOTTOM;
391 view->height += dy; 399 }
392 } else { 400 } else if (mouse_origin.y < midway_y && !pointer_state.lock.top) {
393 sway_log(L_INFO, "Upsizing the view to the top"); 401 changed_floating = true;
394 view->y += dy; 402 view->y += dy;
395 view->height -= dy; 403 view->height -= dy;
396 } 404 edge += WLC_RESIZE_EDGE_TOP;
397 } else if (dy > 0) { 405 }
406 } else if (dy > 0) {
407 if (mouse_origin.y > midway_y && !pointer_state.lock.bottom) {
408 changed_floating = true;
409 view->height += dy;
410 edge += WLC_RESIZE_EDGE_BOTTOM;
411 } else if (!pointer_state.lock.top) {
412 if (view->height > min_sane_h) {
398 changed_floating = true; 413 changed_floating = true;
399 if (mouse_origin.y > midway_y) { 414 view->y += dy;
400 sway_log(L_INFO, "Upsizing to the bottom"); 415 view->height -= dy;
401 view->height += dy; 416 edge += WLC_RESIZE_EDGE_TOP;
402 } else {
403 sway_log(L_INFO, "Downsizing to the bottom");
404 view->y += dy;
405 view->height -= dy;
406 }
407 } 417 }
408 break;
409 } 418 }
410 } 419 }
411 } 420 }
412 } 421 }
413 if (config->focus_follows_mouse && prev_handle != handle) { 422 if (config->focus_follows_mouse && prev_handle != handle) {
414 //Dont change focus if fullscreen 423 // Dont change focus if fullscreen
415 swayc_t *focused = get_focused_view(view); 424 swayc_t *focused = get_focused_view(view);
416 if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)) { 425 if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)
426 && !(pointer_state.l_held || pointer_state.r_held)) {
417 set_focused_container(container_under_pointer()); 427 set_focused_container(container_under_pointer());
418 } 428 }
419 } 429 }
420 prev_handle = handle; 430 prev_handle = handle;
421 prev_pos = mouse_origin; 431 prev_pos = mouse_origin;
422 if (changed_floating) { 432 if (changed_floating) {
423 arrange_windows(view, -1, -1); 433 struct wlc_geometry geometry = {
434 .origin = {
435 .x = view->x,
436 .y = view->y
437 },
438 .size = {
439 .w = view->width,
440 .h = view->height
441 }
442 };
443 wlc_view_set_geometry(view->handle, edge, &geometry);
424 return true; 444 return true;
425 } 445 }
426 return false; 446 return false;
427} 447}
428 448
449
429static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, 450static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
430 uint32_t button, enum wlc_button_state state) { 451 uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) {
431 swayc_t *focused = get_focused_container(&root_container); 452 swayc_t *focused = get_focused_container(&root_container);
432 //dont change focus if fullscreen 453 // dont change focus if fullscreen
433 if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) { 454 if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) {
434 return false; 455 return false;
435 } 456 }
436 if (state == WLC_BUTTON_STATE_PRESSED) { 457 if (state == WLC_BUTTON_STATE_PRESSED) {
437 sway_log(L_DEBUG, "Mouse button %u pressed", button); 458 sway_log(L_DEBUG, "Mouse button %u pressed", button);
438 if (button == 272) { 459 if (button == M_LEFT_CLICK) {
439 m1_held = true; 460 pointer_state.l_held = true;
440 } 461 }
441 if (button == 273) { 462 if (button == M_RIGHT_CLICK) {
442 m2_held = true; 463 pointer_state.r_held = true;
443 } 464 }
444 swayc_t *pointer = container_under_pointer(); 465 swayc_t *pointer = container_under_pointer();
445 set_focused_container(pointer); 466 set_focused_container(pointer);
@@ -453,15 +474,32 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
453 } 474 }
454 } 475 }
455 arrange_windows(pointer->parent, -1, -1); 476 arrange_windows(pointer->parent, -1, -1);
477 if (modifiers->mods & config->floating_mod) {
478 int midway_x = pointer->x + pointer->width/2;
479 int midway_y = pointer->y + pointer->height/2;
480
481 pointer_state.floating.drag = pointer_state.l_held;
482 pointer_state.floating.resize = pointer_state.r_held;
483 pointer_state.lock.bottom = origin->y < midway_y;
484 pointer_state.lock.top = !pointer_state.lock.bottom;
485 pointer_state.lock.right = origin->x < midway_x;
486 pointer_state.lock.left = !pointer_state.lock.right;
487 start_floating(pointer);
488 }
489 // Dont want pointer sent to window while dragging or resizing
490 return (pointer_state.floating.drag || pointer_state.floating.resize);
456 } 491 }
457 return (pointer && pointer != focused); 492 return (pointer && pointer != focused);
458 } else { 493 } else {
459 sway_log(L_DEBUG, "Mouse button %u released", button); 494 sway_log(L_DEBUG, "Mouse button %u released", button);
460 if (button == 272) { 495 if (button == M_LEFT_CLICK) {
461 m1_held = false; 496 pointer_state.l_held = false;
497 pointer_state.floating.drag = false;
462 } 498 }
463 if (button == 273) { 499 if (button == M_RIGHT_CLICK) {
464 m2_held = false; 500 pointer_state.r_held = false;
501 pointer_state.floating.resize = false;
502 pointer_state.lock = (struct pointer_lock){false ,false ,false ,false};
465 } 503 }
466 } 504 }
467 return false; 505 return false;
diff --git a/sway/input_state.c b/sway/input_state.c
new file mode 100644
index 00000000..a7f88d4a
--- /dev/null
+++ b/sway/input_state.c
@@ -0,0 +1,68 @@
1#include <string.h>
2#include <stdbool.h>
3#include <ctype.h>
4
5#include "input_state.h"
6
7#define KEY_STATE_MAX_LENGTH 64
8
9static keycode key_state_array[KEY_STATE_MAX_LENGTH];
10
11static uint8_t find_key(keycode key) {
12 int i;
13 for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) {
14 if (key_state_array[i] == key) {
15 break;
16 }
17 }
18 return i;
19}
20
21bool check_key(keycode key) {
22 return find_key(key) < KEY_STATE_MAX_LENGTH;
23}
24
25void press_key(keycode key) {
26 // Check if key exists
27 if (!check_key(key)) {
28 // Check that we dont exceed buffer length
29 int insert = find_key(0);
30 if (insert < KEY_STATE_MAX_LENGTH) {
31 key_state_array[insert] = key;
32 }
33 }
34}
35
36void release_key(keycode key) {
37 uint8_t index = find_key(key);
38 if (index < KEY_STATE_MAX_LENGTH) {
39 // shift it over and remove key
40 key_state_array[index] = 0;
41 }
42}
43
44struct pointer_state pointer_state = {0, 0, {0, 0}, {0, 0, 0, 0}};
45
46static struct wlc_geometry saved_floating;
47
48void start_floating(swayc_t *view) {
49 if (view->is_floating) {
50 saved_floating.origin.x = view->x;
51 saved_floating.origin.y = view->y;
52 saved_floating.size.w = view->width;
53 saved_floating.size.h = view->height;
54 }
55}
56
57void reset_floating(swayc_t *view) {
58 if (view->is_floating) {
59 view->x = saved_floating.origin.x;
60 view->y = saved_floating.origin.y;
61 view->width = saved_floating.size.w;
62 view->height = saved_floating.size.h;
63 arrange_windows(view->parent, -1, -1);
64 }
65 pointer_state.floating = (struct pointer_floating){0,0};
66 pointer_state.lock = (struct pointer_lock){0,0,0,0};
67}
68
diff --git a/sway/ipc.c b/sway/ipc.c
new file mode 100644
index 00000000..39e580cd
--- /dev/null
+++ b/sway/ipc.c
@@ -0,0 +1,321 @@
1// See https://i3wm.org/docs/ipc.html for protocol information
2
3#include <errno.h>
4#include <string.h>
5#include <sys/socket.h>
6#include <sys/un.h>
7#include <stdbool.h>
8#include <wlc/wlc.h>
9#include <unistd.h>
10#include <stdlib.h>
11#include <stropts.h>
12#include <sys/ioctl.h>
13#include <fcntl.h>
14#include <ctype.h>
15#include "ipc.h"
16#include "log.h"
17#include "config.h"
18#include "commands.h"
19#include "list.h"
20#include "stringop.h"
21
22static int ipc_socket = -1;
23static struct wlc_event_source *ipc_event_source = NULL;
24static struct sockaddr_un ipc_sockaddr = {
25 .sun_family = AF_UNIX,
26 .sun_path = "/tmp/sway-ipc.sock"
27};
28
29static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
30
31struct ipc_client {
32 struct wlc_event_source *event_source;
33 int fd;
34 uint32_t payload_length;
35 enum ipc_command_type current_command;
36};
37
38int ipc_handle_connection(int fd, uint32_t mask, void *data);
39int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
40void ipc_client_disconnect(struct ipc_client *client);
41void ipc_client_handle_command(struct ipc_client *client);
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);
47
48void ipc_init(void) {
49 ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
50 if (ipc_socket == -1) {
51 sway_abort("Unable to create IPC socket");
52 }
53
54 if (getenv("SWAYSOCK") != NULL) {
55 strncpy(ipc_sockaddr.sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr.sun_path));
56 }
57
58 unlink(ipc_sockaddr.sun_path);
59 if (bind(ipc_socket, (struct sockaddr *)&ipc_sockaddr, sizeof(ipc_sockaddr)) == -1) {
60 sway_abort("Unable to bind IPC socket");
61 }
62
63 if (listen(ipc_socket, 3) == -1) {
64 sway_abort("Unable to listen on IPC socket");
65 }
66
67 // Set i3 IPC socket path so that i3-msg works out of the box
68 setenv("I3SOCK", ipc_sockaddr.sun_path, 1);
69
70 ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL);
71}
72
73void ipc_terminate(void) {
74 if (ipc_event_source) {
75 wlc_event_source_remove(ipc_event_source);
76 }
77 close(ipc_socket);
78 unlink(ipc_sockaddr.sun_path);
79}
80
81int ipc_handle_connection(int fd, uint32_t mask, void *data) {
82 (void) fd; (void) data;
83 sway_log(L_DEBUG, "Event on IPC listening socket");
84 assert(mask == WLC_EVENT_READABLE);
85
86 int client_fd = accept(ipc_socket, NULL, NULL);
87 if (client_fd == -1) {
88 sway_log_errno(L_INFO, "Unable to accept IPC client connection");
89 return 0;
90 }
91
92 int flags;
93 if ((flags=fcntl(client_fd, F_GETFD)) == -1 || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
94 sway_log_errno(L_INFO, "Unable to set CLOEXEC on IPC client socket");
95 return 0;
96 }
97
98 struct ipc_client* client = malloc(sizeof(struct ipc_client));
99 client->payload_length = 0;
100 client->fd = client_fd;
101 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client);
102
103 return 0;
104}
105
106static const int ipc_header_size = sizeof(ipc_magic)+8;
107
108int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
109 struct ipc_client *client = data;
110 sway_log(L_DEBUG, "Event on IPC client socket %d", client_fd);
111
112 if (mask & WLC_EVENT_ERROR) {
113 sway_log(L_INFO, "IPC Client socket error, removing client");
114 ipc_client_disconnect(client);
115 return 0;
116 }
117
118 if (mask & WLC_EVENT_HANGUP) {
119 ipc_client_disconnect(client);
120 return 0;
121 }
122
123 int read_available;
124 ioctl(client_fd, FIONREAD, &read_available);
125
126 // Wait for the rest of the command payload in case the header has already been read
127 if (client->payload_length > 0) {
128 if (read_available >= client->payload_length) {
129 ipc_client_handle_command(client);
130 }
131 else {
132 sway_log(L_DEBUG, "Too little data to read payload on IPC Client socket, waiting for more (%d < %d)", read_available, client->payload_length);
133 }
134 return 0;
135 }
136
137 if (read_available < ipc_header_size) {
138 sway_log(L_DEBUG, "Too little data to read header on IPC Client socket, waiting for more (%d < %d)", read_available, ipc_header_size);
139 return 0;
140 }
141
142 char buf[ipc_header_size];
143 ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
144 if (received == -1) {
145 sway_log_errno(L_INFO, "Unable to receive header from IPC client");
146 ipc_client_disconnect(client);
147 return 0;
148 }
149
150 if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) {
151 sway_log(L_DEBUG, "IPC header check failed");
152 ipc_client_disconnect(client);
153 return 0;
154 }
155
156 client->payload_length = *(uint32_t *)&buf[sizeof(ipc_magic)];
157 client->current_command = (enum ipc_command_type) *(uint32_t *)&buf[sizeof(ipc_magic)+4];
158
159 if (read_available - received >= client->payload_length) {
160 ipc_client_handle_command(client);
161 }
162
163 return 0;
164}
165
166void ipc_client_disconnect(struct ipc_client *client)
167{
168 if (!sway_assert(client != NULL, "client != NULL")) {
169 return;
170 }
171
172 sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
173 wlc_event_source_remove(client->event_source);
174 close(client->fd);
175 free(client);
176}
177
178void ipc_client_handle_command(struct ipc_client *client) {
179 if (!sway_assert(client != NULL, "client != NULL")) {
180 return;
181 }
182
183 char buf[client->payload_length + 1];
184 if (client->payload_length > 0)
185 {
186 ssize_t received = recv(client->fd, buf, client->payload_length, 0);
187 if (received == -1)
188 {
189 sway_log_errno(L_INFO, "Unable to receive payload from IPC client");
190 ipc_client_disconnect(client);
191 return;
192 }
193 }
194
195 switch (client->current_command) {
196 case IPC_COMMAND:
197 {
198 buf[client->payload_length] = '\0';
199 bool success = handle_command(config, buf);
200 char reply[64];
201 int length = snprintf(reply, sizeof(reply), "{\"success\":%s}", success ? "true" : "false");
202 ipc_send_reply(client, reply, (uint32_t) length);
203 break;
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 }
225 default:
226 sway_log(L_INFO, "Unknown IPC command type %i", client->current_command);
227 ipc_client_disconnect(client);
228 break;
229 }
230
231 client->payload_length = 0;
232}
233
234bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length) {
235 assert(payload);
236
237 char data[ipc_header_size];
238
239 memcpy(data, ipc_magic, sizeof(ipc_magic));
240 *(uint32_t *)&(data[sizeof(ipc_magic)]) = payload_length;
241 *(uint32_t *)&(data[sizeof(ipc_magic)+4]) = client->current_command;
242
243 if (write(client->fd, data, ipc_header_size) == -1) {
244 sway_log_errno(L_INFO, "Unable to send header to IPC client");
245 ipc_client_disconnect(client);
246 return false;
247 }
248
249 if (write(client->fd, payload, payload_length) == -1) {
250 sway_log_errno(L_INFO, "Unable to send payload to IPC client");
251 ipc_client_disconnect(client);
252 return false;
253 }
254
255 return true;
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 9fdfd62a..a48f15c4 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -4,6 +4,7 @@
4#include "layout.h" 4#include "layout.h"
5#include "log.h" 5#include "log.h"
6#include "list.h" 6#include "list.h"
7#include "config.h"
7#include "container.h" 8#include "container.h"
8#include "workspace.h" 9#include "workspace.h"
9#include "focus.h" 10#include "focus.h"
@@ -32,6 +33,21 @@ void add_child(swayc_t *parent, swayc_t *child) {
32 child->width, child->height, parent, parent->type, parent->width, parent->height); 33 child->width, child->height, parent, parent->type, parent->width, parent->height);
33 list_add(parent->children, child); 34 list_add(parent->children, child);
34 child->parent = parent; 35 child->parent = parent;
36 // set focus for this container
37 if (parent->children->length == 1) {
38 set_focused_container_for(parent, child);
39 }
40}
41
42void add_floating(swayc_t *ws, swayc_t *child) {
43 sway_log(L_DEBUG, "Adding %p (%d, %dx%d) to %p (%d, %dx%d)", child, child->type,
44 child->width, child->height, ws, ws->type, ws->width, ws->height);
45 list_add(ws->floating, child);
46 child->parent = ws;
47 child->is_floating = true;
48 if (!ws->focused) {
49 set_focused_container_for(ws, child);
50 }
35} 51}
36 52
37swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) { 53swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) {
@@ -55,7 +71,7 @@ swayc_t *replace_child(swayc_t *child, swayc_t *new_child) {
55 new_child->parent = child->parent; 71 new_child->parent = child->parent;
56 72
57 if (child->parent->focused == child) { 73 if (child->parent->focused == child) {
58 child->parent->focused = new_child; 74 set_focused_container_for(child->parent, new_child);
59 } 75 }
60 child->parent = NULL; 76 child->parent = NULL;
61 return parent; 77 return parent;
@@ -72,6 +88,7 @@ swayc_t *remove_child(swayc_t *child) {
72 break; 88 break;
73 } 89 }
74 } 90 }
91 i = 0;
75 } else { 92 } else {
76 for (i = 0; i < parent->children->length; ++i) { 93 for (i = 0; i < parent->children->length; ++i) {
77 if (parent->children->items[i] == child) { 94 if (parent->children->items[i] == child) {
@@ -80,7 +97,7 @@ swayc_t *remove_child(swayc_t *child) {
80 } 97 }
81 } 98 }
82 } 99 }
83 //Set focused to new container 100 // Set focused to new container
84 if (parent->focused == child) { 101 if (parent->focused == child) {
85 if (parent->children->length > 0) { 102 if (parent->children->length > 0) {
86 set_focused_container_for(parent, parent->children->items[i?i-1:0]); 103 set_focused_container_for(parent, parent->children->items[i?i-1:0]);
@@ -104,7 +121,7 @@ void move_container(swayc_t *container,swayc_t* root,int direction){
104 //Only one container, meh. 121 //Only one container, meh.
105 break; 122 break;
106 } 123 }
107 124 //TODO: Implement horizontal movement.
108 //TODO: Implement move to a different workspace. 125 //TODO: Implement move to a different workspace.
109 if(direction == MOVE_LEFT && i > 0){ 126 if(direction == MOVE_LEFT && i > 0){
110 temp = root->children->items[i-1]; 127 temp = root->children->items[i-1];
@@ -167,11 +184,11 @@ void arrange_windows(swayc_t *container, int width, int height) {
167 // y -= container->y; 184 // y -= container->y;
168 for (i = 0; i < container->children->length; ++i) { 185 for (i = 0; i < container->children->length; ++i) {
169 swayc_t *child = container->children->items[i]; 186 swayc_t *child = container->children->items[i];
170 sway_log(L_DEBUG, "Arranging workspace #%d", i); 187 child->x = x + container->gaps;
171 child->x = x; 188 child->y = y + container->gaps;
172 child->y = y; 189 child->width = width - container->gaps * 2;
173 child->width = width; 190 child->height = height - container->gaps * 2;
174 child->height = height; 191 sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y);
175 arrange_windows(child, -1, -1); 192 arrange_windows(child, -1, -1);
176 } 193 }
177 return; 194 return;
@@ -179,27 +196,24 @@ void arrange_windows(swayc_t *container, int width, int height) {
179 { 196 {
180 struct wlc_geometry geometry = { 197 struct wlc_geometry geometry = {
181 .origin = { 198 .origin = {
182 .x = container->x, 199 .x = container->x + container->gaps / 2,
183 .y = container->y 200 .y = container->y + container->gaps / 2
184 }, 201 },
185 .size = { 202 .size = {
186 .w = width, 203 .w = width - container->gaps,
187 .h = height 204 .h = height - container->gaps
188 } 205 }
189 }; 206 };
190 if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { 207 if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
191 swayc_t *parent = container; 208 swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
192 while (parent->type != C_OUTPUT) {
193 parent = parent->parent;
194 }
195 geometry.origin.x = 0; 209 geometry.origin.x = 0;
196 geometry.origin.y = 0; 210 geometry.origin.y = 0;
197 geometry.size.w = parent->width; 211 geometry.size.w = parent->width;
198 geometry.size.h = parent->height; 212 geometry.size.h = parent->height;
199 wlc_view_set_geometry(container->handle, &geometry); 213 wlc_view_set_geometry(container->handle, 0, &geometry);
200 wlc_view_bring_to_front(container->handle); 214 wlc_view_bring_to_front(container->handle);
201 } else { 215 } else {
202 wlc_view_set_geometry(container->handle, &geometry); 216 wlc_view_set_geometry(container->handle, 0, &geometry);
203 container->width = width; 217 container->width = width;
204 container->height = height; 218 container->height = height;
205 } 219 }
@@ -213,40 +227,62 @@ void arrange_windows(swayc_t *container, int width, int height) {
213 break; 227 break;
214 } 228 }
215 229
216 double total_weight = 0; 230 x = y = 0;
217 for (i = 0; i < container->children->length; ++i) { 231 double scale = 0;
218 swayc_t *child = container->children->items[i];
219 total_weight += child->weight;
220 }
221
222 switch (container->layout) { 232 switch (container->layout) {
223 case L_HORIZ: 233 case L_HORIZ:
224 default: 234 default:
225 sway_log(L_DEBUG, "Arranging %p horizontally", container); 235 // Calculate total width
226 for (i = 0; i < container->children->length; ++i) { 236 for (i = 0; i < container->children->length; ++i) {
227 swayc_t *child = container->children->items[i]; 237 int *old_width = &((swayc_t *)container->children->items[i])->width;
228 double percent = child->weight / total_weight; 238 if (*old_width <= 0) {
229 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width); 239 if (container->children->length > 1) {
230 child->x = x + container->x; 240 *old_width = width / (container->children->length - 1);
231 child->y = y + container->y; 241 } else {
232 int w = width * percent; 242 *old_width = width;
233 int h = height; 243 }
234 arrange_windows(child, w, h); 244 }
235 x += w; 245 scale += *old_width;
246 }
247 // Resize windows
248 if (scale > 0.1) {
249 scale = width / scale;
250 sway_log(L_DEBUG, "Arranging %p horizontally", container);
251 for (i = 0; i < container->children->length; ++i) {
252 swayc_t *child = container->children->items[i];
253 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, width, scale);
254 child->x = x + container->x;
255 child->y = y + container->y;
256 arrange_windows(child, child->width * scale, height);
257 x += child->width;
258 }
236 } 259 }
237 break; 260 break;
238 case L_VERT: 261 case L_VERT:
239 sway_log(L_DEBUG, "Arranging %p vertically", container); 262 // Calculate total height
240 for (i = 0; i < container->children->length; ++i) { 263 for (i = 0; i < container->children->length; ++i) {
241 swayc_t *child = container->children->items[i]; 264 int *old_height = &((swayc_t *)container->children->items[i])->height;
242 double percent = child->weight / total_weight; 265 if (*old_height <= 0) {
243 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will receive %.2f of %d)", child, child->type, percent, width); 266 if (container->children->length > 1) {
244 child->x = x + container->x; 267 *old_height = height / (container->children->length - 1);
245 child->y = y + container->y; 268 } else {
246 int w = width; 269 *old_height = height;
247 int h = height * percent; 270 }
248 arrange_windows(child, w, h); 271 }
249 y += h; 272 scale += *old_height;
273 }
274 // Resize
275 if (scale > 0.1) {
276 scale = height / scale;
277 sway_log(L_DEBUG, "Arranging %p vertically", container);
278 for (i = 0; i < container->children->length; ++i) {
279 swayc_t *child = container->children->items[i];
280 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, height, scale);
281 child->x = x + container->x;
282 child->y = y + container->y;
283 arrange_windows(child, width, child->height * scale);
284 y += child->height;
285 }
250 } 286 }
251 break; 287 break;
252 } 288 }
@@ -268,20 +304,15 @@ void arrange_windows(swayc_t *container, int width, int height) {
268 } 304 }
269 }; 305 };
270 if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { 306 if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) {
271 swayc_t *parent = view; 307 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
272 while (parent->type != C_OUTPUT) {
273 parent = parent->parent;
274 }
275 geometry.origin.x = 0; 308 geometry.origin.x = 0;
276 geometry.origin.y = 0; 309 geometry.origin.y = 0;
277 geometry.size.w = parent->width; 310 geometry.size.w = parent->width;
278 geometry.size.h = parent->height; 311 geometry.size.h = parent->height;
279 wlc_view_set_geometry(view->handle, &geometry); 312 wlc_view_set_geometry(view->handle, 0, &geometry);
280 wlc_view_bring_to_front(view->handle); 313 wlc_view_bring_to_front(view->handle);
281 } else { 314 } else {
282 wlc_view_set_geometry(view->handle, &geometry); 315 wlc_view_set_geometry(view->handle, 0, &geometry);
283 view->width = width;
284 view->height = height;
285 // Bring the views to the front in order of the list, the list 316 // Bring the views to the front in order of the list, the list
286 // will be kept up to date so that more recently focused views 317 // will be kept up to date so that more recently focused views
287 // have higher indexes 318 // have higher indexes
@@ -326,3 +357,54 @@ swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) {
326 } 357 }
327 return NULL; 358 return NULL;
328} 359}
360
361swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir) {
362 swayc_t *parent = container->parent;
363
364 if (dir == MOVE_PARENT) {
365 if (parent->type == C_OUTPUT) {
366 return NULL;
367 } else {
368 return parent;
369 }
370 }
371 while (true) {
372 // Test if we can even make a difference here
373 bool can_move = false;
374 int diff = 0;
375 if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
376 if (parent->layout == L_HORIZ || parent->type == C_ROOT) {
377 can_move = true;
378 diff = dir == MOVE_LEFT ? -1 : 1;
379 }
380 } else {
381 if (parent->layout == L_VERT) {
382 can_move = true;
383 diff = dir == MOVE_UP ? -1 : 1;
384 }
385 }
386 if (can_move) {
387 int i;
388 for (i = 0; i < parent->children->length; ++i) {
389 swayc_t *child = parent->children->items[i];
390 if (child == container) {
391 break;
392 }
393 }
394 int desired = i + diff;
395 if (desired < 0 || desired >= parent->children->length) {
396 can_move = false;
397 } else {
398 return parent->children->items[desired];
399 }
400 }
401 if (!can_move) {
402 container = parent;
403 parent = parent->parent;
404 if (!parent) {
405 // Nothing we can do
406 return NULL;
407 }
408 }
409 }
410}
diff --git a/sway/log.c b/sway/log.c
index 8e380ffe..6e01421b 100644
--- a/sway/log.c
+++ b/sway/log.c
@@ -1,9 +1,13 @@
1#include "log.h" 1#include "log.h"
2#include "sway.h"
2#include <stdarg.h> 3#include <stdarg.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <fcntl.h> 6#include <fcntl.h>
6#include <unistd.h> 7#include <unistd.h>
8#include <signal.h>
9#include <errno.h>
10#include <string.h>
7 11
8int colored = 1; 12int colored = 1;
9int v = 0; 13int v = 0;
@@ -18,10 +22,10 @@ static const char *verbosity_colors[] = {
18void init_log(int verbosity) { 22void init_log(int verbosity) {
19 v = verbosity; 23 v = verbosity;
20 /* set FD_CLOEXEC flag to prevent programs called with exec to write into logs */ 24 /* set FD_CLOEXEC flag to prevent programs called with exec to write into logs */
21 int i, flag; 25 int i;
22 int fd[] = { STDOUT_FILENO, STDIN_FILENO, STDERR_FILENO }; 26 int fd[] = { STDOUT_FILENO, STDIN_FILENO, STDERR_FILENO };
23 for (i = 0; i < 3; ++i) { 27 for (i = 0; i < 3; ++i) {
24 flag = fcntl(fd[i], F_GETFD); 28 int flag = fcntl(fd[i], F_GETFD);
25 if (flag != -1) { 29 if (flag != -1) {
26 fcntl(fd[i], F_SETFD, flag | FD_CLOEXEC); 30 fcntl(fd[i], F_SETFD, flag | FD_CLOEXEC);
27 } 31 }
@@ -32,17 +36,17 @@ void sway_log_colors(int mode) {
32 colored = (mode == 1) ? 1 : 0; 36 colored = (mode == 1) ? 1 : 0;
33} 37}
34 38
35void sway_abort(char *format, ...) { 39void sway_abort(const char *format, ...) {
36 fprintf(stderr, "ERROR: "); 40 fprintf(stderr, "ERROR: ");
37 va_list args; 41 va_list args;
38 va_start(args, format); 42 va_start(args, format);
39 vfprintf(stderr, format, args); 43 vfprintf(stderr, format, args);
40 va_end(args); 44 va_end(args);
41 fprintf(stderr, "\n"); 45 fprintf(stderr, "\n");
42 exit(1); 46 sway_terminate();
43} 47}
44 48
45void sway_log(int verbosity, char* format, ...) { 49void sway_log(int verbosity, const char* format, ...) {
46 if (verbosity <= v) { 50 if (verbosity <= v) {
47 int c = verbosity; 51 int c = verbosity;
48 if (c > sizeof(verbosity_colors) / sizeof(char *)) { 52 if (c > sizeof(verbosity_colors) / sizeof(char *)) {
@@ -64,3 +68,106 @@ void sway_log(int verbosity, char* format, ...) {
64 fprintf(stderr, "\n"); 68 fprintf(stderr, "\n");
65 } 69 }
66} 70}
71
72void sway_log_errno(int verbosity, char* format, ...) {
73 if (verbosity <= v) {
74 int c = verbosity;
75 if (c > sizeof(verbosity_colors) / sizeof(char *)) {
76 c = sizeof(verbosity_colors) / sizeof(char *) - 1;
77 }
78
79 if (colored) {
80 fprintf(stderr, verbosity_colors[c]);
81 }
82
83 va_list args;
84 va_start(args, format);
85 vfprintf(stderr, format, args);
86 va_end(args);
87
88 fprintf(stderr, ": ");
89 char error[256];
90 strerror_r(errno, error, sizeof(error));
91 fprintf(stderr, error);
92
93 if (colored) {
94 fprintf(stderr, "\x1B[0m");
95 }
96 fprintf(stderr, "\n");
97 }
98}
99
100bool sway_assert(bool condition, const char* format, ...) {
101 if (condition) {
102 return true;
103 }
104
105#ifndef NDEBUG
106 raise(SIGABRT);
107#endif
108
109 va_list args;
110 va_start(args, format);
111 sway_log(L_ERROR, format, args);
112 va_end(args);
113
114 return false;
115}
116
117#include "workspace.h"
118
119/* XXX:DEBUG:XXX */
120static void container_log(const swayc_t *c) {
121 fprintf(stderr, "focus:%c|",
122 c->is_focused ? 'F' : // Focused
123 c == active_workspace ? 'W' : // active workspace
124 c == &root_container ? 'R' : // root
125 'X');// not any others
126 fprintf(stderr,"(%p)",c);
127 fprintf(stderr,"(p:%p)",c->parent);
128 fprintf(stderr,"(f:%p)",c->focused);
129 fprintf(stderr,"(h:%ld)",c->handle);
130 fprintf(stderr,"Type:");
131 fprintf(stderr,
132 c->type == C_ROOT ? "Root|" :
133 c->type == C_OUTPUT ? "Output|" :
134 c->type == C_WORKSPACE ? "Workspace|" :
135 c->type == C_CONTAINER ? "Container|" :
136 c->type == C_VIEW ? "View|" : "Unknown|");
137 fprintf(stderr,"layout:");
138 fprintf(stderr,
139 c->layout == L_NONE ? "NONE|" :
140 c->layout == L_HORIZ ? "Horiz|":
141 c->layout == L_VERT ? "Vert|":
142 c->layout == L_STACKED ? "Stacked|":
143 c->layout == L_FLOATING ? "Floating|":
144 "Unknown|");
145 fprintf(stderr, "w:%d|h:%d|", c->width, c->height);
146 fprintf(stderr, "x:%d|y:%d|", c->x, c->y);
147 fprintf(stderr, "vis:%c|", c->visible?'t':'f');
148 fprintf(stderr, "name:%.16s|", c->name);
149 fprintf(stderr, "children:%d\n",c->children?c->children->length:0);
150}
151void layout_log(const swayc_t *c, int depth) {
152 int i, d;
153 int e = c->children ? c->children->length : 0;
154 container_log(c);
155 if (e) {
156 for (i = 0; i < e; ++i) {
157 fputc('|',stderr);
158 for (d = 0; d < depth; ++d) fputc('-', stderr);
159 layout_log(c->children->items[i], depth + 1);
160 }
161 }
162 if (c->type == C_WORKSPACE) {
163 e = c->floating?c->floating->length:0;
164 if (e) {
165 for (i = 0; i < e; ++i) {
166 fputc('|',stderr);
167 for (d = 0; d < depth; ++d) fputc('=', stderr);
168 layout_log(c->floating->items[i], depth + 1);
169 }
170 }
171 }
172}
173/* XXX:DEBUG:XXX */
diff --git a/sway/main.c b/sway/main.c
index 2db4604c..f37f086d 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -4,31 +4,121 @@
4#include <wlc/wlc.h> 4#include <wlc/wlc.h>
5#include <sys/wait.h> 5#include <sys/wait.h>
6#include <signal.h> 6#include <signal.h>
7#include <getopt.h>
7#include "layout.h" 8#include "layout.h"
8#include "config.h" 9#include "config.h"
9#include "log.h" 10#include "log.h"
10#include "handlers.h" 11#include "handlers.h"
12#include "ipc.h"
13#include "sway.h"
14
15static bool terminate_request = false;
16
17void sway_terminate(void) {
18 terminate_request = true;
19 wlc_terminate();
20}
11 21
12static void sigchld_handle(int signal); 22static void sigchld_handle(int signal);
13 23
14int main(int argc, char **argv) { 24int main(int argc, char **argv) {
25 static int verbose = 0, debug = 0, validate = 0;
26
27 static struct option long_options[] = {
28 {"config", required_argument, NULL, 'c'},
29 {"validate", no_argument, &validate, 1},
30 {"debug", no_argument, &debug, 1},
31 {"version", no_argument, NULL, 'v'},
32 {"verbose", no_argument, &verbose, 1},
33 {"get-socketpath", no_argument, NULL, 'p'},
34 };
35
15 /* Signal handling */ 36 /* Signal handling */
16 signal(SIGCHLD, sigchld_handle); 37 signal(SIGCHLD, sigchld_handle);
17 38
18 setenv("WLC_DIM", "0", 0); 39 setenv("WLC_DIM", "0", 0);
40
41 FILE *devnull = fopen("/dev/null", "w");
42 if (devnull) {
43 // NOTE: Does not work, see wlc issue #54
44 wlc_set_log_file(devnull);
45 }
46
19 /* Changing code earlier than this point requires detailed review */ 47 /* Changing code earlier than this point requires detailed review */
20 if (!wlc_init(&interface, argc, argv)) { 48 if (!wlc_init(&interface, argc, argv)) {
21 return 1; 49 return 1;
22 } 50 }
23 51
24 init_log(L_DEBUG); // TODO: Control this with command line arg 52 char *config_path = NULL;
53
54 int c;
55 while (1) {
56 int option_index = 0;
57 c = getopt_long(argc, argv, "CdvVpc:", long_options, &option_index);
58 if (c == -1) {
59 break;
60 }
61 switch (c) {
62 case 0: // Flag
63 break;
64 case 'c': // config
65 config_path = strdup(optarg);
66 break;
67 case 'C': // validate
68 validate = 1;
69 break;
70 case 'd': // debug
71 debug = 1;
72 break;
73 case 'v': // version
74 // todo
75 exit(0);
76 break;
77 case 'V': // verbose
78 verbose = 1;
79 break;
80 case 'p': // --get-socketpath
81 // TODO
82 break;
83 }
84 }
85
86 if (debug) {
87 init_log(L_DEBUG);
88 wlc_set_log_file(stderr);
89 fclose(devnull);
90 devnull = NULL;
91 } else if (verbose || validate) {
92 init_log(L_INFO);
93 } else {
94 init_log(L_ERROR);
95 }
96
97 if (validate) {
98 bool valid = load_config(config_path);
99 return valid ? 0 : 1;
100 }
101
25 init_layout(); 102 init_layout();
26 103
27 if (!load_config()) { 104 if (!load_config(config_path)) {
28 sway_log(L_ERROR, "Error(s) loading config!"); 105 sway_log(L_ERROR, "Error(s) loading config!");
29 } 106 }
107 if (config_path) {
108 free(config_path);
109 }
110
111 ipc_init();
112
113 if (!terminate_request) {
114 wlc_run();
115 }
116
117 if (devnull) {
118 fclose(devnull);
119 }
30 120
31 wlc_run(); 121 ipc_terminate();
32 122
33 return 0; 123 return 0;
34} 124}
diff --git a/sway/readline.c b/sway/readline.c
index dfdc3fe8..e75b183f 100644
--- a/sway/readline.c
+++ b/sway/readline.c
@@ -17,18 +17,22 @@ char *read_line(FILE *file) {
17 continue; 17 continue;
18 } 18 }
19 if (length == size) { 19 if (length == size) {
20 string = realloc(string, size *= 2); 20 char *new_string = realloc(string, size *= 2);
21 if (!string) { 21 if (!new_string) {
22 free(string);
22 return NULL; 23 return NULL;
23 } 24 }
25 string = new_string;
24 } 26 }
25 string[length++] = c; 27 string[length++] = c;
26 } 28 }
27 if (length + 1 == size) { 29 if (length + 1 == size) {
28 string = realloc(string, length + 1); 30 char *new_string = realloc(string, length + 1);
29 if (!string) { 31 if (!new_string) {
32 free(string);
30 return NULL; 33 return NULL;
31 } 34 }
35 string = new_string;
32 } 36 }
33 string[length] = '\0'; 37 string[length] = '\0';
34 return string; 38 return string;
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 05a669fe..d436da8e 100644
--- a/sway/workspace.c
+++ b/sway/workspace.c
@@ -31,7 +31,7 @@ char *workspace_next_name(void) {
31 char* target = malloc(strlen(args->items[1]) + 1); 31 char* target = malloc(strlen(args->items[1]) + 1);
32 strcpy(target, args->items[1]); 32 strcpy(target, args->items[1]);
33 while (*target == ' ' || *target == '\t') 33 while (*target == ' ' || *target == '\t')
34 target++; 34 target++;
35 35
36 // Make sure that the command references an actual workspace 36 // Make sure that the command references an actual workspace
37 // not a command about workspaces 37 // not a command about workspaces
@@ -42,11 +42,15 @@ char *workspace_next_name(void) {
42 strcmp(target, "number") == 0 || 42 strcmp(target, "number") == 0 ||
43 strcmp(target, "back_and_forth") == 0 || 43 strcmp(target, "back_and_forth") == 0 ||
44 strcmp(target, "current") == 0) 44 strcmp(target, "current") == 0)
45 {
46 list_free(args);
45 continue; 47 continue;
46 48 }
47 //Make sure that the workspace doesn't already exist 49
50 // Make sure that the workspace doesn't already exist
48 if (workspace_find_by_name(target)) { 51 if (workspace_find_by_name(target)) {
49 continue; 52 list_free(args);
53 continue;
50 } 54 }
51 55
52 list_free(args); 56 list_free(args);
@@ -54,6 +58,7 @@ char *workspace_next_name(void) {
54 sway_log(L_DEBUG, "Workspace: Found free name %s", target); 58 sway_log(L_DEBUG, "Workspace: Found free name %s", target);
55 return target; 59 return target;
56 } 60 }
61 list_free(args);
57 } 62 }
58 // As a fall back, get the current number of active workspaces 63 // As a fall back, get the current number of active workspaces
59 // and return that + 1 for the next workspace's name 64 // and return that + 1 for the next workspace's name
@@ -70,14 +75,12 @@ char *workspace_next_name(void) {
70 75
71swayc_t *workspace_create(const char* name) { 76swayc_t *workspace_create(const char* name) {
72 swayc_t *parent = get_focused_container(&root_container); 77 swayc_t *parent = get_focused_container(&root_container);
73 while (parent->type != C_OUTPUT) { 78 parent = swayc_parent_by_type(parent, C_OUTPUT);
74 parent = parent->parent;
75 }
76 return new_workspace(parent, name); 79 return new_workspace(parent, name);
77} 80}
78 81
79bool workspace_by_name(swayc_t *view, void *data) { 82bool workspace_by_name(swayc_t *view, void *data) {
80 return (view->type == C_WORKSPACE) && 83 return (view->type == C_WORKSPACE) &&
81 (strcasecmp(view->name, (char *) data) == 0); 84 (strcasecmp(view->name, (char *) data) == 0);
82} 85}
83 86
@@ -180,62 +183,4 @@ void workspace_switch(swayc_t *workspace) {
180 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); 183 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
181 set_focused_container(get_focused_view(workspace)); 184 set_focused_container(get_focused_view(workspace));
182 arrange_windows(workspace, -1, -1); 185 arrange_windows(workspace, -1, -1);
183 active_workspace = workspace;
184}
185
186/* XXX:DEBUG:XXX */
187static void container_log(const swayc_t *c) {
188 fprintf(stderr, "focus:%c|",
189 c->is_focused ? 'F' : //Focused
190 c == active_workspace ? 'W' : //active workspace
191 c == &root_container ? 'R' : //root
192 'X');//not any others
193 fprintf(stderr,"(%p)",c);
194 fprintf(stderr,"(p:%p)",c->parent);
195 fprintf(stderr,"(f:%p)",c->focused);
196 fprintf(stderr,"(h:%ld)",c->handle);
197 fprintf(stderr,"Type:");
198 fprintf(stderr,
199 c->type == C_ROOT ? "Root|" :
200 c->type == C_OUTPUT ? "Output|" :
201 c->type == C_WORKSPACE ? "Workspace|" :
202 c->type == C_CONTAINER ? "Container|" :
203 c->type == C_VIEW ? "View|" : "Unknown|");
204 fprintf(stderr,"layout:");
205 fprintf(stderr,
206 c->layout == L_NONE ? "NONE|" :
207 c->layout == L_HORIZ ? "Horiz|":
208 c->layout == L_VERT ? "Vert|":
209 c->layout == L_STACKED ? "Stacked|":
210 c->layout == L_FLOATING ? "Floating|":
211 "Unknown|");
212 fprintf(stderr, "w:%d|h:%d|", c->width, c->height);
213 fprintf(stderr, "x:%d|y:%d|", c->x, c->y);
214 fprintf(stderr, "vis:%c|", c->visible?'t':'f');
215 fprintf(stderr, "wgt:%d|", c->weight);
216 fprintf(stderr, "name:%.16s|", c->name);
217 fprintf(stderr, "children:%d\n",c->children?c->children->length:0);
218}
219void layout_log(const swayc_t *c, int depth) {
220 int i, d;
221 int e = c->children ? c->children->length : 0;
222 container_log(c);
223 if (e) {
224 for (i = 0; i < e; ++i) {
225 fputc('|',stderr);
226 for (d = 0; d < depth; ++d) fputc('-', stderr);
227 layout_log(c->children->items[i], depth + 1);
228 }
229 }
230 if (c->type == C_WORKSPACE) {
231 e = c->floating?c->floating->length:0;
232 if (e) {
233 for (i = 0; i < e; ++i) {
234 fputc('|',stderr);
235 for (d = 0; d < depth; ++d) fputc('-', stderr);
236 layout_log(c->floating->items[i], depth + 1);
237 }
238 }
239 }
240} 186}
241/* XXX:DEBUG:XXX */