summaryrefslogtreecommitdiffstats
path: root/sway/commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands.c')
-rw-r--r--sway/commands.c186
1 files changed, 140 insertions, 46 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 }