summaryrefslogtreecommitdiffstats
path: root/sway/commands
diff options
context:
space:
mode:
authorLibravatar emersion <contact@emersion.fr>2018-08-02 23:49:25 +0100
committerLibravatar GitHub <noreply@github.com>2018-08-02 23:49:25 +0100
commit3a54e2291c017397ceff60511c29fe70d229bc8b (patch)
treed340b7776f945462f5ecffc830ada4d5fbe82f51 /sway/commands
parentEnable wlr-gamma-control-unstable-v1 (diff)
parentMerge pull request #2411 from emersion/fullscreen-pointer-input (diff)
downloadsway-3a54e2291c017397ceff60511c29fe70d229bc8b.tar.gz
sway-3a54e2291c017397ceff60511c29fe70d229bc8b.tar.zst
sway-3a54e2291c017397ceff60511c29fe70d229bc8b.zip
Merge branch 'master' into wlr-gamma-control
Diffstat (limited to 'sway/commands')
-rw-r--r--sway/commands/bind.c218
-rw-r--r--sway/commands/exec_always.c6
-rw-r--r--sway/commands/floating.c21
-rw-r--r--sway/commands/floating_modifier.c30
-rw-r--r--sway/commands/focus.c25
-rw-r--r--sway/commands/focus_follows_mouse.c4
-rw-r--r--sway/commands/focus_wrapping.c12
-rw-r--r--sway/commands/force_focus_wrapping.c8
-rw-r--r--sway/commands/fullscreen.c28
-rw-r--r--sway/commands/input.c21
-rw-r--r--sway/commands/input/drag_lock.c9
-rw-r--r--sway/commands/input/dwt.c9
-rw-r--r--sway/commands/input/left_handed.c11
-rw-r--r--sway/commands/input/middle_emulation.c9
-rw-r--r--sway/commands/input/natural_scroll.c11
-rw-r--r--sway/commands/input/tap.c9
-rw-r--r--sway/commands/input/xkb_capslock.c33
-rw-r--r--sway/commands/input/xkb_numlock.c33
-rw-r--r--sway/commands/mark.c2
-rw-r--r--sway/commands/mode.c1
-rw-r--r--sway/commands/move.c43
-rw-r--r--sway/commands/output/dpms.c8
-rw-r--r--sway/commands/reload.c29
-rw-r--r--sway/commands/scratchpad.c44
-rw-r--r--sway/commands/show_marks.c10
-rw-r--r--sway/commands/split.c4
-rw-r--r--sway/commands/swap.c7
-rw-r--r--sway/commands/urgent.c10
28 files changed, 494 insertions, 161 deletions
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 83e9e432..8270b958 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -1,3 +1,4 @@
1#define _XOPEN_SOURCE 500
1#ifdef __linux__ 2#ifdef __linux__
2#include <linux/input-event-codes.h> 3#include <linux/input-event-codes.h>
3#elif __FreeBSD__ 4#elif __FreeBSD__
@@ -5,9 +6,11 @@
5#endif 6#endif
6#include <xkbcommon/xkbcommon.h> 7#include <xkbcommon/xkbcommon.h>
7#include <xkbcommon/xkbcommon-names.h> 8#include <xkbcommon/xkbcommon-names.h>
9#include <string.h>
8#include <strings.h> 10#include <strings.h>
9#include "sway/commands.h" 11#include "sway/commands.h"
10#include "sway/config.h" 12#include "sway/config.h"
13#include "sway/ipc-server.h"
11#include "list.h" 14#include "list.h"
12#include "log.h" 15#include "log.h"
13#include "stringop.h" 16#include "stringop.h"
@@ -27,6 +30,33 @@ void free_sway_binding(struct sway_binding *binding) {
27 free(binding); 30 free(binding);
28} 31}
29 32
33static struct sway_binding *sway_binding_dup(struct sway_binding *sb) {
34 struct sway_binding *new_sb = calloc(1, sizeof(struct sway_binding));
35 if (!new_sb) {
36 return NULL;
37 }
38
39 new_sb->type = sb->type;
40 new_sb->order = sb->order;
41 new_sb->flags = sb->flags;
42 new_sb->modifiers = sb->modifiers;
43 new_sb->command = strdup(sb->command);
44
45 new_sb->keys = create_list();
46 int i;
47 for (i = 0; i < sb->keys->length; ++i) {
48 xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t));
49 if (!key) {
50 free_sway_binding(new_sb);
51 return NULL;
52 }
53 *key = *(xkb_keysym_t *)sb->keys->items[i];
54 list_add(new_sb->keys, key);
55 }
56
57 return new_sb;
58}
59
30/** 60/**
31 * Returns true if the bindings have the same key and modifier combinations. 61 * Returns true if the bindings have the same key and modifier combinations.
32 * Note that keyboard layout is not considered, so the bindings might actually 62 * Note that keyboard layout is not considered, so the bindings might actually
@@ -34,11 +64,14 @@ void free_sway_binding(struct sway_binding *binding) {
34 */ 64 */
35static bool binding_key_compare(struct sway_binding *binding_a, 65static bool binding_key_compare(struct sway_binding *binding_a,
36 struct sway_binding *binding_b) { 66 struct sway_binding *binding_b) {
37 if (binding_a->release != binding_b->release) { 67 if (binding_a->type != binding_b->type) {
38 return false; 68 return false;
39 } 69 }
40 70
41 if (binding_a->bindcode != binding_b->bindcode) { 71 uint32_t conflict_generating_flags = BINDING_RELEASE | BINDING_BORDER
72 | BINDING_CONTENTS | BINDING_TITLEBAR;
73 if ((binding_a->flags & conflict_generating_flags) !=
74 (binding_b->flags & conflict_generating_flags)) {
42 return false; 75 return false;
43 } 76 }
44 77
@@ -69,6 +102,66 @@ static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) {
69 return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); 102 return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0);
70} 103}
71 104
105
106/**
107 * From a keycode, bindcode, or bindsym name and the most likely binding type,
108 * identify the appropriate numeric value corresponding to the key. Return NULL
109 * and set *key_val if successful, otherwise return a specific error. Change
110 * the value of *type if the initial type guess was incorrect and if this
111 * was the first identified key.
112 */
113static struct cmd_results *identify_key(const char* name, bool first_key,
114 uint32_t* key_val, enum binding_input_type* type) {
115 if (*type == BINDING_KEYCODE) {
116 // check for keycode
117 xkb_keycode_t keycode = strtol(name, NULL, 10);
118 if (!xkb_keycode_is_legal_ext(keycode)) {
119 return cmd_results_new(CMD_INVALID, "bindcode",
120 "Invalid keycode '%s'", name);
121 }
122 *key_val = keycode;
123 } else {
124 // check for keysym
125 xkb_keysym_t keysym = xkb_keysym_from_name(name,
126 XKB_KEYSYM_CASE_INSENSITIVE);
127
128 // Check for mouse binding
129 uint32_t button = 0;
130 if (strncasecmp(name, "button", strlen("button")) == 0 &&
131 strlen(name) == strlen("button0")) {
132 button = name[strlen("button")] - '1' + BTN_LEFT;
133 }
134
135 if (*type == BINDING_KEYSYM) {
136 if (button) {
137 if (first_key) {
138 *type = BINDING_MOUSE;
139 *key_val = button;
140 } else {
141 return cmd_results_new(CMD_INVALID, "bindsym",
142 "Mixed button '%s' into key sequence", name);
143 }
144 } else if (keysym) {
145 *key_val = keysym;
146 } else {
147 return cmd_results_new(CMD_INVALID, "bindsym",
148 "Unknown key '%s'", name);
149 }
150 } else {
151 if (button) {
152 *key_val = button;
153 } else if (keysym) {
154 return cmd_results_new(CMD_INVALID, "bindsym",
155 "Mixed keysym '%s' into button sequence", name);
156 } else {
157 return cmd_results_new(CMD_INVALID, "bindsym",
158 "Unknown button '%s'", name);
159 }
160 }
161 }
162 return NULL;
163}
164
72static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, 165static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
73 bool bindcode) { 166 bool bindcode) {
74 const char *bindtype = bindcode ? "bindcode" : "bindsym"; 167 const char *bindtype = bindcode ? "bindcode" : "bindsym";
@@ -85,22 +178,34 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
85 } 178 }
86 binding->keys = create_list(); 179 binding->keys = create_list();
87 binding->modifiers = 0; 180 binding->modifiers = 0;
88 binding->release = false; 181 binding->flags = 0;
89 binding->locked = false; 182 binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM;
90 binding->bindcode = bindcode; 183
184 bool exclude_titlebar = false;
91 185
92 // Handle --release and --locked 186 // Handle --release and --locked
93 while (argc > 0) { 187 while (argc > 0) {
94 if (strcmp("--release", argv[0]) == 0) { 188 if (strcmp("--release", argv[0]) == 0) {
95 binding->release = true; 189 binding->flags |= BINDING_RELEASE;
96 } else if (strcmp("--locked", argv[0]) == 0) { 190 } else if (strcmp("--locked", argv[0]) == 0) {
97 binding->locked = true; 191 binding->flags |= BINDING_LOCKED;
192 } else if (strcmp("--whole-window", argv[0]) == 0) {
193 binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR;
194 } else if (strcmp("--border", argv[0]) == 0) {
195 binding->flags |= BINDING_BORDER;
196 } else if (strcmp("--exclude-titlebar", argv[0]) == 0) {
197 exclude_titlebar = true;
98 } else { 198 } else {
99 break; 199 break;
100 } 200 }
101 argv++; 201 argv++;
102 argc--; 202 argc--;
103 } 203 }
204 if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR)
205 || exclude_titlebar) {
206 binding->type = BINDING_MOUSE;
207 }
208
104 if (argc < 2) { 209 if (argc < 2) {
105 free_sway_binding(binding); 210 free_sway_binding(binding);
106 return cmd_results_new(CMD_FAILURE, bindtype, 211 return cmd_results_new(CMD_FAILURE, bindtype,
@@ -119,64 +224,47 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
119 continue; 224 continue;
120 } 225 }
121 226
122 xkb_keycode_t keycode; 227 // Identify the key and possibly change binding->type
123 xkb_keysym_t keysym; 228 uint32_t key_val = 0;
124 if (bindcode) { 229 error = identify_key(split->items[i], binding->keys->length == 0,
125 // parse keycode 230 &key_val, &binding->type);
126 keycode = (int)strtol(split->items[i], NULL, 10); 231 if (error) {
127 if (!xkb_keycode_is_legal_ext(keycode)) { 232 free_sway_binding(binding);
128 error = 233 list_free(split);
129 cmd_results_new(CMD_INVALID, "bindcode", 234 return error;
130 "Invalid keycode '%s'", (char *)split->items[i]);
131 free_sway_binding(binding);
132 list_free(split);
133 return error;
134 }
135 } else {
136 // Check for xkb key
137 keysym = xkb_keysym_from_name(split->items[i],
138 XKB_KEYSYM_CASE_INSENSITIVE);
139
140 // Check for mouse binding
141 if (strncasecmp(split->items[i], "button", strlen("button")) == 0 &&
142 strlen(split->items[i]) == strlen("button0")) {
143 keysym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT;
144 }
145 if (!keysym) {
146 struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym",
147 "Unknown key '%s'", (char *)split->items[i]);
148 free_sway_binding(binding);
149 free_flat_list(split);
150 return ret;
151 }
152 } 235 }
236
153 uint32_t *key = calloc(1, sizeof(uint32_t)); 237 uint32_t *key = calloc(1, sizeof(uint32_t));
154 if (!key) { 238 if (!key) {
155 free_sway_binding(binding); 239 free_sway_binding(binding);
156 free_flat_list(split); 240 free_flat_list(split);
157 return cmd_results_new(CMD_FAILURE, bindtype, 241 return cmd_results_new(CMD_FAILURE, bindtype,
158 "Unable to allocate binding"); 242 "Unable to allocate binding key");
159 }
160
161 if (bindcode) {
162 *key = (uint32_t)keycode;
163 } else {
164 *key = (uint32_t)keysym;
165 } 243 }
166 244 *key = key_val;
167 list_add(binding->keys, key); 245 list_add(binding->keys, key);
168 } 246 }
169 free_flat_list(split); 247 free_flat_list(split);
170 binding->order = binding_order++; 248 binding->order = binding_order++;
171 249
250 // refine region of interest for mouse binding once we are certain
251 // that this is one
252 if (exclude_titlebar) {
253 binding->flags &= ~BINDING_TITLEBAR;
254 } else if (binding->type == BINDING_MOUSE) {
255 binding->flags |= BINDING_TITLEBAR;
256 }
257
172 // sort ascending 258 // sort ascending
173 list_qsort(binding->keys, key_qsort_cmp); 259 list_qsort(binding->keys, key_qsort_cmp);
174 260
175 list_t *mode_bindings; 261 list_t *mode_bindings;
176 if (bindcode) { 262 if (binding->type == BINDING_KEYCODE) {
177 mode_bindings = config->current_mode->keycode_bindings; 263 mode_bindings = config->current_mode->keycode_bindings;
178 } else { 264 } else if (binding->type == BINDING_KEYSYM) {
179 mode_bindings = config->current_mode->keysym_bindings; 265 mode_bindings = config->current_mode->keysym_bindings;
266 } else {
267 mode_bindings = config->current_mode->mouse_bindings;
180 } 268 }
181 269
182 // overwrite the binding if it already exists 270 // overwrite the binding if it already exists
@@ -209,3 +297,39 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
209struct cmd_results *cmd_bindcode(int argc, char **argv) { 297struct cmd_results *cmd_bindcode(int argc, char **argv) {
210 return cmd_bindsym_or_bindcode(argc, argv, true); 298 return cmd_bindsym_or_bindcode(argc, argv, true);
211} 299}
300
301
302/**
303 * Execute the command associated to a binding
304 */
305void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) {
306 wlr_log(WLR_DEBUG, "running command for binding: %s",
307 binding->command);
308
309 struct sway_binding *binding_copy = binding;
310 bool reload = false;
311 // if this is a reload command we need to make a duplicate of the
312 // binding since it will be gone after the reload has completed.
313 if (strcasecmp(binding->command, "reload") == 0) {
314 reload = true;
315 binding_copy = sway_binding_dup(binding);
316 if (!binding_copy) {
317 wlr_log(WLR_ERROR, "Failed to duplicate binding during reload");
318 return;
319 }
320 }
321
322 config->handler_context.seat = seat;
323 struct cmd_results *results = execute_command(binding->command, NULL);
324 if (results->status == CMD_SUCCESS) {
325 ipc_event_binding(binding_copy);
326 } else {
327 wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
328 binding->command, results->error);
329 }
330
331 if (reload) { // free the binding if we made a copy
332 free_sway_binding(binding_copy);
333 }
334 free_cmd_results(results);
335}
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
index c7727857..c730cb8b 100644
--- a/sway/commands/exec_always.c
+++ b/sway/commands/exec_always.c
@@ -4,6 +4,7 @@
4#include <string.h> 4#include <string.h>
5#include <sys/wait.h> 5#include <sys/wait.h>
6#include <unistd.h> 6#include <unistd.h>
7#include <signal.h>
7#include "sway/commands.h" 8#include "sway/commands.h"
8#include "sway/config.h" 9#include "sway/config.h"
9#include "sway/tree/container.h" 10#include "sway/tree/container.h"
@@ -47,6 +48,9 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
47 if ((pid = fork()) == 0) { 48 if ((pid = fork()) == 0) {
48 // Fork child process again 49 // Fork child process again
49 setsid(); 50 setsid();
51 sigset_t set;
52 sigemptyset(&set);
53 sigprocmask(SIG_SETMASK, &set, NULL);
50 close(fd[0]); 54 close(fd[0]);
51 if ((child = fork()) == 0) { 55 if ((child = fork()) == 0) {
52 close(fd[1]); 56 close(fd[1]);
@@ -74,7 +78,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
74 waitpid(pid, NULL, 0); 78 waitpid(pid, NULL, 0);
75 if (child > 0) { 79 if (child > 0) {
76 wlr_log(WLR_DEBUG, "Child process created with pid %d", child); 80 wlr_log(WLR_DEBUG, "Child process created with pid %d", child);
77 // TODO: add PID to active workspace 81 workspace_record_pid(child);
78 } else { 82 } else {
79 return cmd_results_new(CMD_FAILURE, "exec_always", 83 return cmd_results_new(CMD_FAILURE, "exec_always",
80 "Second fork() failed"); 84 "Second fork() failed");
diff --git a/sway/commands/floating.c b/sway/commands/floating.c
index 6ab56c3b..31de5ec3 100644
--- a/sway/commands/floating.c
+++ b/sway/commands/floating.c
@@ -17,9 +17,24 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
17 } 17 }
18 struct sway_container *container = 18 struct sway_container *container =
19 config->handler_context.current_container; 19 config->handler_context.current_container;
20 if (container->type != C_VIEW) { 20 if (container->type == C_WORKSPACE && container->children->length == 0) {
21 // TODO: This doesn't strictly speaking have to be true 21 return cmd_results_new(CMD_INVALID, "floating",
22 return cmd_results_new(CMD_INVALID, "float", "Only views can float"); 22 "Can't float an empty workspace");
23 }
24 if (container->type == C_WORKSPACE) {
25 // Wrap the workspace's children in a container so we can float it
26 struct sway_container *workspace = container;
27 container = container_wrap_children(container);
28 workspace->layout = L_HORIZ;
29 seat_set_focus(config->handler_context.seat, container);
30 }
31
32 // If the container is in a floating split container,
33 // operate on the split container instead of the child.
34 if (container_is_floating_or_child(container)) {
35 while (container->parent->layout != L_FLOATING) {
36 container = container->parent;
37 }
23 } 38 }
24 39
25 bool wants_floating; 40 bool wants_floating;
diff --git a/sway/commands/floating_modifier.c b/sway/commands/floating_modifier.c
new file mode 100644
index 00000000..f5d2b3fe
--- /dev/null
+++ b/sway/commands/floating_modifier.c
@@ -0,0 +1,30 @@
1#include "strings.h"
2#include "sway/commands.h"
3#include "sway/config.h"
4#include "util.h"
5
6struct cmd_results *cmd_floating_modifier(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "floating_modifier", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11
12 uint32_t mod = get_modifier_mask_by_name(argv[0]);
13 if (!mod) {
14 return cmd_results_new(CMD_INVALID, "floating_modifier",
15 "Invalid modifier");
16 }
17
18 if (argc == 1 || strcasecmp(argv[1], "normal") == 0) {
19 config->floating_mod_inverse = false;
20 } else if (strcasecmp(argv[1], "inverse") == 0) {
21 config->floating_mod_inverse = true;
22 } else {
23 return cmd_results_new(CMD_INVALID, "floating_modifier",
24 "Usage: floating_modifier <mod> [inverse|normal]");
25 }
26
27 config->floating_mod = mod;
28
29 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
30}
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 9cd8bfae..76d3f1dc 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -35,14 +35,25 @@ static struct cmd_results *focus_mode(struct sway_container *con,
35 struct sway_seat *seat, bool floating) { 35 struct sway_seat *seat, bool floating) {
36 struct sway_container *ws = con->type == C_WORKSPACE ? 36 struct sway_container *ws = con->type == C_WORKSPACE ?
37 con : container_parent(con, C_WORKSPACE); 37 con : container_parent(con, C_WORKSPACE);
38 struct sway_container *new_focus = ws; 38
39 if (floating) { 39 // If the container is in a floating split container,
40 new_focus = ws->sway_workspace->floating; 40 // operate on the split container instead of the child.
41 if (new_focus->children->length == 0) { 41 if (container_is_floating_or_child(con)) {
42 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 42 while (con->parent->layout != L_FLOATING) {
43 con = con->parent;
43 } 44 }
44 } 45 }
45 seat_set_focus(seat, seat_get_active_child(seat, new_focus)); 46
47 struct sway_container *new_focus = NULL;
48 if (floating) {
49 new_focus = seat_get_focus_inactive(seat, ws->sway_workspace->floating);
50 } else {
51 new_focus = seat_get_focus_inactive_tiling(seat, ws);
52 }
53 if (!new_focus) {
54 new_focus = ws;
55 }
56 seat_set_focus(seat, new_focus);
46 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 57 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
47} 58}
48 59
@@ -97,7 +108,7 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
97 } else if (strcmp(argv[0], "tiling") == 0) { 108 } else if (strcmp(argv[0], "tiling") == 0) {
98 return focus_mode(con, seat, false); 109 return focus_mode(con, seat, false);
99 } else if (strcmp(argv[0], "mode_toggle") == 0) { 110 } else if (strcmp(argv[0], "mode_toggle") == 0) {
100 return focus_mode(con, seat, !container_is_floating(con)); 111 return focus_mode(con, seat, !container_is_floating_or_child(con));
101 } 112 }
102 113
103 if (strcmp(argv[0], "output") == 0) { 114 if (strcmp(argv[0], "output") == 0) {
diff --git a/sway/commands/focus_follows_mouse.c b/sway/commands/focus_follows_mouse.c
index 661e7852..0b0e334c 100644
--- a/sway/commands/focus_follows_mouse.c
+++ b/sway/commands/focus_follows_mouse.c
@@ -1,12 +1,14 @@
1#include <string.h> 1#include <string.h>
2#include <strings.h> 2#include <strings.h>
3#include "sway/commands.h" 3#include "sway/commands.h"
4#include "util.h"
4 5
5struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) { 6struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) {
6 struct cmd_results *error = NULL; 7 struct cmd_results *error = NULL;
7 if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) { 8 if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) {
8 return error; 9 return error;
9 } 10 }
10 config->focus_follows_mouse = !strcasecmp(argv[0], "yes"); 11 config->focus_follows_mouse =
12 parse_boolean(argv[0], config->focus_follows_mouse);
11 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 13 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
12} 14}
diff --git a/sway/commands/focus_wrapping.c b/sway/commands/focus_wrapping.c
index 0a9e0bf2..562ee4f9 100644
--- a/sway/commands/focus_wrapping.c
+++ b/sway/commands/focus_wrapping.c
@@ -1,6 +1,7 @@
1#include <strings.h> 1#include <strings.h>
2#include "sway/commands.h" 2#include "sway/commands.h"
3#include "sway/config.h" 3#include "sway/config.h"
4#include "util.h"
4 5
5struct cmd_results *cmd_focus_wrapping(int argc, char **argv) { 6struct cmd_results *cmd_focus_wrapping(int argc, char **argv) {
6 struct cmd_results *error = NULL; 7 struct cmd_results *error = NULL;
@@ -8,15 +9,12 @@ struct cmd_results *cmd_focus_wrapping(int argc, char **argv) {
8 return error; 9 return error;
9 } 10 }
10 11
11 if (strcasecmp(argv[0], "no") == 0) { 12 if (strcasecmp(argv[0], "force") == 0) {
12 config->focus_wrapping = WRAP_NO;
13 } else if (strcasecmp(argv[0], "yes") == 0) {
14 config->focus_wrapping = WRAP_YES;
15 } else if (strcasecmp(argv[0], "force") == 0) {
16 config->focus_wrapping = WRAP_FORCE; 13 config->focus_wrapping = WRAP_FORCE;
14 } else if (parse_boolean(argv[0], config->focus_wrapping == WRAP_YES)) {
15 config->focus_wrapping = WRAP_YES;
17 } else { 16 } else {
18 return cmd_results_new(CMD_INVALID, "focus_wrapping", 17 config->focus_wrapping = WRAP_NO;
19 "Expected 'focus_wrapping yes|no|force'");
20 } 18 }
21 19
22 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 20 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/force_focus_wrapping.c b/sway/commands/force_focus_wrapping.c
index bc1d067f..0892d9e9 100644
--- a/sway/commands/force_focus_wrapping.c
+++ b/sway/commands/force_focus_wrapping.c
@@ -1,6 +1,7 @@
1#include <strings.h> 1#include <strings.h>
2#include "sway/commands.h" 2#include "sway/commands.h"
3#include "sway/config.h" 3#include "sway/config.h"
4#include "util.h"
4 5
5struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { 6struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) {
6 struct cmd_results *error = 7 struct cmd_results *error =
@@ -9,13 +10,10 @@ struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) {
9 return error; 10 return error;
10 } 11 }
11 12
12 if (strcasecmp(argv[0], "no") == 0) { 13 if (parse_boolean(argv[0], config->focus_wrapping == WRAP_FORCE)) {
13 config->focus_wrapping = WRAP_YES;
14 } else if (strcasecmp(argv[0], "yes") == 0) {
15 config->focus_wrapping = WRAP_FORCE; 14 config->focus_wrapping = WRAP_FORCE;
16 } else { 15 } else {
17 return cmd_results_new(CMD_INVALID, "force_focus_wrapping", 16 config->focus_wrapping = WRAP_YES;
18 "Expected 'force_focus_wrapping yes|no'");
19 } 17 }
20 18
21 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 19 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
index 0b5beaa2..5ad06e40 100644
--- a/sway/commands/fullscreen.c
+++ b/sway/commands/fullscreen.c
@@ -5,6 +5,7 @@
5#include "sway/tree/container.h" 5#include "sway/tree/container.h"
6#include "sway/tree/view.h" 6#include "sway/tree/view.h"
7#include "sway/tree/layout.h" 7#include "sway/tree/layout.h"
8#include "util.h"
8 9
9struct cmd_results *cmd_fullscreen(int argc, char **argv) { 10struct cmd_results *cmd_fullscreen(int argc, char **argv) {
10 struct cmd_results *error = NULL; 11 struct cmd_results *error = NULL;
@@ -13,25 +14,24 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
13 } 14 }
14 struct sway_container *container = 15 struct sway_container *container =
15 config->handler_context.current_container; 16 config->handler_context.current_container;
16 if (container->type != C_VIEW) { 17 if (container->type == C_WORKSPACE && container->children->length == 0) {
17 return cmd_results_new(CMD_INVALID, "fullscreen", 18 return cmd_results_new(CMD_INVALID, "fullscreen",
18 "Only views can fullscreen"); 19 "Can't fullscreen an empty workspace");
19 } 20 }
20 struct sway_view *view = container->sway_view; 21 if (container->type == C_WORKSPACE) {
21 bool wants_fullscreen; 22 // Wrap the workspace's children in a container so we can fullscreen it
23 struct sway_container *workspace = container;
24 container = container_wrap_children(container);
25 workspace->layout = L_HORIZ;
26 seat_set_focus(config->handler_context.seat, container);
27 }
28 bool enable = !container->is_fullscreen;
22 29
23 if (argc == 0 || strcmp(argv[0], "toggle") == 0) { 30 if (argc) {
24 wants_fullscreen = !view->is_fullscreen; 31 enable = parse_boolean(argv[0], container->is_fullscreen);
25 } else if (strcmp(argv[0], "enable") == 0) {
26 wants_fullscreen = true;
27 } else if (strcmp(argv[0], "disable") == 0) {
28 wants_fullscreen = false;
29 } else {
30 return cmd_results_new(CMD_INVALID, "fullscreen",
31 "Expected 'fullscreen' or 'fullscreen <enable|disable|toggle>'");
32 } 32 }
33 33
34 view_set_fullscreen(view, wants_fullscreen); 34 container_set_fullscreen(container, enable);
35 35
36 struct sway_container *workspace = container_parent(container, C_WORKSPACE); 36 struct sway_container *workspace = container_parent(container, C_WORKSPACE);
37 arrange_windows(workspace->parent); 37 arrange_windows(workspace->parent);
diff --git a/sway/commands/input.c b/sway/commands/input.c
index 5b203ea0..84888fbb 100644
--- a/sway/commands/input.c
+++ b/sway/commands/input.c
@@ -31,6 +31,12 @@ static struct cmd_handler input_handlers[] = {
31 { "xkb_variant", input_cmd_xkb_variant }, 31 { "xkb_variant", input_cmd_xkb_variant },
32}; 32};
33 33
34// must be in order for the bsearch
35static struct cmd_handler input_config_handlers[] = {
36 { "xkb_capslock", input_cmd_xkb_capslock },
37 { "xkb_numlock", input_cmd_xkb_numlock },
38};
39
34struct cmd_results *cmd_input(int argc, char **argv) { 40struct cmd_results *cmd_input(int argc, char **argv) {
35 struct cmd_results *error = NULL; 41 struct cmd_results *error = NULL;
36 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { 42 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) {
@@ -44,8 +50,21 @@ struct cmd_results *cmd_input(int argc, char **argv) {
44 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config"); 50 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
45 } 51 }
46 52
47 struct cmd_results *res = config_subcommand(argv + 1, argc - 1, 53 struct cmd_results *res;
54
55 if (find_handler(argv[1], input_config_handlers,
56 sizeof(input_config_handlers))) {
57 if (config->reading) {
58 res = config_subcommand(argv + 1, argc - 1,
59 input_config_handlers, sizeof(input_config_handlers));
60 } else {
61 res = cmd_results_new(CMD_FAILURE, "input",
62 "Can only be used in config file.");
63 }
64 } else {
65 res = config_subcommand(argv + 1, argc - 1,
48 input_handlers, sizeof(input_handlers)); 66 input_handlers, sizeof(input_handlers));
67 }
49 68
50 free_input_config(config->handler_context.input_config); 69 free_input_config(config->handler_context.input_config);
51 config->handler_context.input_config = NULL; 70 config->handler_context.input_config = NULL;
diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c
index 9e32816f..f9ddeef2 100644
--- a/sway/commands/input/drag_lock.c
+++ b/sway/commands/input/drag_lock.c
@@ -3,6 +3,7 @@
3#include "sway/config.h" 3#include "sway/config.h"
4#include "sway/commands.h" 4#include "sway/commands.h"
5#include "sway/input/input-manager.h" 5#include "sway/input/input-manager.h"
6#include "util.h"
6 7
7struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { 8struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
8 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
@@ -18,14 +19,10 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
18 struct input_config *new_config = 19 struct input_config *new_config =
19 new_input_config(current_input_config->identifier); 20 new_input_config(current_input_config->identifier);
20 21
21 if (strcasecmp(argv[0], "enabled") == 0) { 22 if (parse_boolean(argv[0], true)) {
22 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; 23 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
23 } else if (strcasecmp(argv[0], "disabled") == 0) {
24 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
25 } else { 24 } else {
26 free_input_config(new_config); 25 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
27 return cmd_results_new(CMD_INVALID, "drag_lock",
28 "Expected 'drag_lock <enabled|disabled>'");
29 } 26 }
30 27
31 apply_input_config(new_config); 28 apply_input_config(new_config);
diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c
index 73937507..15134268 100644
--- a/sway/commands/input/dwt.c
+++ b/sway/commands/input/dwt.c
@@ -3,6 +3,7 @@
3#include "sway/config.h" 3#include "sway/config.h"
4#include "sway/commands.h" 4#include "sway/commands.h"
5#include "sway/input/input-manager.h" 5#include "sway/input/input-manager.h"
6#include "util.h"
6 7
7struct cmd_results *input_cmd_dwt(int argc, char **argv) { 8struct cmd_results *input_cmd_dwt(int argc, char **argv) {
8 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
@@ -17,14 +18,10 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) {
17 struct input_config *new_config = 18 struct input_config *new_config =
18 new_input_config(current_input_config->identifier); 19 new_input_config(current_input_config->identifier);
19 20
20 if (strcasecmp(argv[0], "enabled") == 0) { 21 if (parse_boolean(argv[0], true)) {
21 new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; 22 new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
22 } else if (strcasecmp(argv[0], "disabled") == 0) {
23 new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
24 } else { 23 } else {
25 free_input_config(new_config); 24 new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
26 return cmd_results_new(CMD_INVALID, "dwt",
27 "Expected 'dwt <enabled|disabled>'");
28 } 25 }
29 26
30 apply_input_config(new_config); 27 apply_input_config(new_config);
diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c
index 769ce98c..e770043a 100644
--- a/sway/commands/input/left_handed.c
+++ b/sway/commands/input/left_handed.c
@@ -3,6 +3,7 @@
3#include "sway/config.h" 3#include "sway/config.h"
4#include "sway/commands.h" 4#include "sway/commands.h"
5#include "sway/input/input-manager.h" 5#include "sway/input/input-manager.h"
6#include "util.h"
6 7
7struct cmd_results *input_cmd_left_handed(int argc, char **argv) { 8struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
8 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
@@ -18,15 +19,7 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
18 struct input_config *new_config = 19 struct input_config *new_config =
19 new_input_config(current_input_config->identifier); 20 new_input_config(current_input_config->identifier);
20 21
21 if (strcasecmp(argv[0], "enabled") == 0) { 22 new_config->left_handed = parse_boolean(argv[0], true);
22 new_config->left_handed = 1;
23 } else if (strcasecmp(argv[0], "disabled") == 0) {
24 new_config->left_handed = 0;
25 } else {
26 free_input_config(new_config);
27 return cmd_results_new(CMD_INVALID, "left_handed",
28 "Expected 'left_handed <enabled|disabled>'");
29 }
30 23
31 apply_input_config(new_config); 24 apply_input_config(new_config);
32 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 25 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c
index 7ca01629..414d4d2b 100644
--- a/sway/commands/input/middle_emulation.c
+++ b/sway/commands/input/middle_emulation.c
@@ -3,6 +3,7 @@
3#include "sway/config.h" 3#include "sway/config.h"
4#include "sway/commands.h" 4#include "sway/commands.h"
5#include "sway/input/input-manager.h" 5#include "sway/input/input-manager.h"
6#include "util.h"
6 7
7struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { 8struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
8 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
@@ -18,15 +19,11 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
18 struct input_config *new_config = 19 struct input_config *new_config =
19 new_input_config(current_input_config->identifier); 20 new_input_config(current_input_config->identifier);
20 21
21 if (strcasecmp(argv[0], "enabled") == 0) { 22 if (parse_boolean(argv[0], true)) {
22 new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; 23 new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
23 } else if (strcasecmp(argv[0], "disabled") == 0) { 24 } else {
24 new_config->middle_emulation = 25 new_config->middle_emulation =
25 LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; 26 LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
26 } else {
27 free_input_config(new_config);
28 return cmd_results_new(CMD_INVALID, "middle_emulation",
29 "Expected 'middle_emulation <enabled|disabled>'");
30 } 27 }
31 28
32 apply_input_config(new_config); 29 apply_input_config(new_config);
diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c
index 55236790..77c3ff00 100644
--- a/sway/commands/input/natural_scroll.c
+++ b/sway/commands/input/natural_scroll.c
@@ -3,6 +3,7 @@
3#include "sway/config.h" 3#include "sway/config.h"
4#include "sway/commands.h" 4#include "sway/commands.h"
5#include "sway/input/input-manager.h" 5#include "sway/input/input-manager.h"
6#include "util.h"
6 7
7struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { 8struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
8 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
@@ -18,15 +19,7 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
18 struct input_config *new_config = 19 struct input_config *new_config =
19 new_input_config(current_input_config->identifier); 20 new_input_config(current_input_config->identifier);
20 21
21 if (strcasecmp(argv[0], "enabled") == 0) { 22 new_config->natural_scroll = parse_boolean(argv[0], true);
22 new_config->natural_scroll = 1;
23 } else if (strcasecmp(argv[0], "disabled") == 0) {
24 new_config->natural_scroll = 0;
25 } else {
26 free_input_config(new_config);
27 return cmd_results_new(CMD_INVALID, "natural_scroll",
28 "Expected 'natural_scroll <enabled|disabled>'");
29 }
30 23
31 apply_input_config(new_config); 24 apply_input_config(new_config);
32 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 25 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c
index a8d1a10c..ac3b8237 100644
--- a/sway/commands/input/tap.c
+++ b/sway/commands/input/tap.c
@@ -4,6 +4,7 @@
4#include "sway/commands.h" 4#include "sway/commands.h"
5#include "sway/input/input-manager.h" 5#include "sway/input/input-manager.h"
6#include "log.h" 6#include "log.h"
7#include "util.h"
7 8
8struct cmd_results *input_cmd_tap(int argc, char **argv) { 9struct cmd_results *input_cmd_tap(int argc, char **argv) {
9 struct cmd_results *error = NULL; 10 struct cmd_results *error = NULL;
@@ -18,14 +19,10 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) {
18 struct input_config *new_config = 19 struct input_config *new_config =
19 new_input_config(current_input_config->identifier); 20 new_input_config(current_input_config->identifier);
20 21
21 if (strcasecmp(argv[0], "enabled") == 0) { 22 if (parse_boolean(argv[0], true)) {
22 new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; 23 new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED;
23 } else if (strcasecmp(argv[0], "disabled") == 0) {
24 new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
25 } else { 24 } else {
26 free_input_config(new_config); 25 new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
27 return cmd_results_new(CMD_INVALID, "tap",
28 "Expected 'tap <enabled|disabled>'");
29 } 26 }
30 27
31 wlr_log(WLR_DEBUG, "apply-tap for device: %s", 28 wlr_log(WLR_DEBUG, "apply-tap for device: %s",
diff --git a/sway/commands/input/xkb_capslock.c b/sway/commands/input/xkb_capslock.c
new file mode 100644
index 00000000..5442c463
--- /dev/null
+++ b/sway/commands/input/xkb_capslock.c
@@ -0,0 +1,33 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_xkb_capslock(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "xkb_capslock", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
14 if (!current_input_config) {
15 return cmd_results_new(CMD_FAILURE, "xkb_capslock",
16 "No input device defined.");
17 }
18 struct input_config *new_config =
19 new_input_config(current_input_config->identifier);
20
21 if (strcasecmp(argv[0], "enabled") == 0) {
22 new_config->xkb_capslock = 1;
23 } else if (strcasecmp(argv[0], "disabled") == 0) {
24 new_config->xkb_capslock = 0;
25 } else {
26 free_input_config(new_config);
27 return cmd_results_new(CMD_INVALID, "xkb_capslock",
28 "Expected 'xkb_capslock <enabled|disabled>'");
29 }
30
31 apply_input_config(new_config);
32 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
33}
diff --git a/sway/commands/input/xkb_numlock.c b/sway/commands/input/xkb_numlock.c
new file mode 100644
index 00000000..39675366
--- /dev/null
+++ b/sway/commands/input/xkb_numlock.c
@@ -0,0 +1,33 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/config.h"
4#include "sway/commands.h"
5#include "sway/input/input-manager.h"
6
7struct cmd_results *input_cmd_xkb_numlock(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "xkb_numlock", EXPECTED_AT_LEAST, 1))) {
10 return error;
11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
14 if (!current_input_config) {
15 return cmd_results_new(CMD_FAILURE, "xkb_numlock",
16 "No input device defined.");
17 }
18 struct input_config *new_config =
19 new_input_config(current_input_config->identifier);
20
21 if (strcasecmp(argv[0], "enabled") == 0) {
22 new_config->xkb_numlock = 1;
23 } else if (strcasecmp(argv[0], "disabled") == 0) {
24 new_config->xkb_numlock = 0;
25 } else {
26 free_input_config(new_config);
27 return cmd_results_new(CMD_INVALID, "xkb_numlock",
28 "Expected 'xkb_numlock <enabled|disabled>'");
29 }
30
31 apply_input_config(new_config);
32 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
33}
diff --git a/sway/commands/mark.c b/sway/commands/mark.c
index 5a897e69..9ea8c301 100644
--- a/sway/commands/mark.c
+++ b/sway/commands/mark.c
@@ -58,7 +58,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
58 view_find_and_unmark(mark); 58 view_find_and_unmark(mark);
59 59
60 if (!toggle || !had_mark) { 60 if (!toggle || !had_mark) {
61 list_add(view->marks, strdup(mark)); 61 view_add_mark(view, mark);
62 } 62 }
63 63
64 free(mark); 64 free(mark);
diff --git a/sway/commands/mode.c b/sway/commands/mode.c
index b460fcb5..637ca45e 100644
--- a/sway/commands/mode.c
+++ b/sway/commands/mode.c
@@ -56,6 +56,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
56 mode->name = strdup(mode_name); 56 mode->name = strdup(mode_name);
57 mode->keysym_bindings = create_list(); 57 mode->keysym_bindings = create_list();
58 mode->keycode_bindings = create_list(); 58 mode->keycode_bindings = create_list();
59 mode->mouse_bindings = create_list();
59 mode->pango = pango; 60 mode->pango = pango;
60 list_add(config->modes, mode); 61 list_add(config->modes, mode);
61 } 62 }
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 6ec050a8..702b42d9 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -9,6 +9,7 @@
9#include "sway/input/cursor.h" 9#include "sway/input/cursor.h"
10#include "sway/input/seat.h" 10#include "sway/input/seat.h"
11#include "sway/output.h" 11#include "sway/output.h"
12#include "sway/scratchpad.h"
12#include "sway/tree/arrange.h" 13#include "sway/tree/arrange.h"
13#include "sway/tree/container.h" 14#include "sway/tree/container.h"
14#include "sway/tree/layout.h" 15#include "sway/tree/layout.h"
@@ -58,8 +59,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
58 && strcasecmp(argv[2], "workspace") == 0) { 59 && strcasecmp(argv[2], "workspace") == 0) {
59 // move container to workspace x 60 // move container to workspace x
60 if (current->type == C_WORKSPACE) { 61 if (current->type == C_WORKSPACE) {
61 // TODO: Wrap children in a container and move that 62 current = container_wrap_children(current);
62 return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
63 } else if (current->type != C_CONTAINER && current->type != C_VIEW) { 63 } else if (current->type != C_CONTAINER && current->type != C_VIEW) {
64 return cmd_results_new(CMD_FAILURE, "move", 64 return cmd_results_new(CMD_FAILURE, "move",
65 "Can only move containers and views."); 65 "Can only move containers and views.");
@@ -97,7 +97,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
97 container_move_to(current, destination); 97 container_move_to(current, destination);
98 struct sway_container *focus = seat_get_focus_inactive( 98 struct sway_container *focus = seat_get_focus_inactive(
99 config->handler_context.seat, old_parent); 99 config->handler_context.seat, old_parent);
100 seat_set_focus(config->handler_context.seat, focus); 100 seat_set_focus_warp(config->handler_context.seat, focus, true, false);
101 container_reap_empty(old_parent); 101 container_reap_empty(old_parent);
102 container_reap_empty(destination->parent); 102 container_reap_empty(destination->parent);
103 103
@@ -134,7 +134,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
134 struct sway_container *old_parent = current->parent; 134 struct sway_container *old_parent = current->parent;
135 struct sway_container *old_ws = container_parent(current, C_WORKSPACE); 135 struct sway_container *old_ws = container_parent(current, C_WORKSPACE);
136 container_move_to(current, focus); 136 container_move_to(current, focus);
137 seat_set_focus(config->handler_context.seat, old_parent); 137 seat_set_focus_warp(config->handler_context.seat, old_parent, true, false);
138 container_reap_empty(old_parent); 138 container_reap_empty(old_parent);
139 container_reap_empty(focus->parent); 139 container_reap_empty(focus->parent);
140 140
@@ -195,7 +195,7 @@ static struct cmd_results *move_in_direction(struct sway_container *container,
195 "Cannot move workspaces in a direction"); 195 "Cannot move workspaces in a direction");
196 } 196 }
197 if (container_is_floating(container)) { 197 if (container_is_floating(container)) {
198 if (container->type == C_VIEW && container->sway_view->is_fullscreen) { 198 if (container->is_fullscreen) {
199 return cmd_results_new(CMD_FAILURE, "move", 199 return cmd_results_new(CMD_FAILURE, "move",
200 "Cannot move fullscreen floating container"); 200 "Cannot move fullscreen floating container");
201 } 201 }
@@ -296,6 +296,34 @@ static struct cmd_results *move_to_position(struct sway_container *container,
296 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 296 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
297} 297}
298 298
299static struct cmd_results *move_to_scratchpad(struct sway_container *con) {
300 if (con->type == C_WORKSPACE && con->children->length == 0) {
301 return cmd_results_new(CMD_INVALID, "move",
302 "Can't move an empty workspace to the scratchpad");
303 }
304 if (con->type == C_WORKSPACE) {
305 // Wrap the workspace's children in a container
306 struct sway_container *workspace = con;
307 con = container_wrap_children(con);
308 workspace->layout = L_HORIZ;
309 }
310
311 // If the container is in a floating split container,
312 // operate on the split container instead of the child.
313 if (container_is_floating_or_child(con)) {
314 while (con->parent->layout != L_FLOATING) {
315 con = con->parent;
316 }
317 }
318
319 if (con->scratchpad) {
320 return cmd_results_new(CMD_INVALID, "move",
321 "Container is already in the scratchpad");
322 }
323 scratchpad_add_container(con);
324 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
325}
326
299struct cmd_results *cmd_move(int argc, char **argv) { 327struct cmd_results *cmd_move(int argc, char **argv) {
300 struct cmd_results *error = NULL; 328 struct cmd_results *error = NULL;
301 if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { 329 if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
@@ -317,10 +345,9 @@ struct cmd_results *cmd_move(int argc, char **argv) {
317 } else if (strcasecmp(argv[0], "workspace") == 0) { 345 } else if (strcasecmp(argv[0], "workspace") == 0) {
318 return cmd_move_workspace(current, argc, argv); 346 return cmd_move_workspace(current, argc, argv);
319 } else if (strcasecmp(argv[0], "scratchpad") == 0 347 } else if (strcasecmp(argv[0], "scratchpad") == 0
320 || (strcasecmp(argv[0], "to") == 0 348 || (strcasecmp(argv[0], "to") == 0 && argc == 2
321 && strcasecmp(argv[1], "scratchpad") == 0)) { 349 && strcasecmp(argv[1], "scratchpad") == 0)) {
322 // TODO: scratchpad 350 return move_to_scratchpad(current);
323 return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
324 } else if (strcasecmp(argv[0], "position") == 0) { 351 } else if (strcasecmp(argv[0], "position") == 0) {
325 return move_to_position(current, argc, argv); 352 return move_to_position(current, argc, argv);
326 } else if (strcasecmp(argv[0], "absolute") == 0) { 353 } else if (strcasecmp(argv[0], "absolute") == 0) {
diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c
index 0959ea6b..3492061e 100644
--- a/sway/commands/output/dpms.c
+++ b/sway/commands/output/dpms.c
@@ -1,5 +1,6 @@
1#include "sway/commands.h" 1#include "sway/commands.h"
2#include "sway/config.h" 2#include "sway/config.h"
3#include "util.h"
3 4
4struct cmd_results *output_cmd_dpms(int argc, char **argv) { 5struct cmd_results *output_cmd_dpms(int argc, char **argv) {
5 if (!config->handler_context.output_config) { 6 if (!config->handler_context.output_config) {
@@ -9,13 +10,10 @@ struct cmd_results *output_cmd_dpms(int argc, char **argv) {
9 return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument."); 10 return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument.");
10 } 11 }
11 12
12 if (strcmp(*argv, "on") == 0) { 13 if (parse_boolean(argv[0], true)) {
13 config->handler_context.output_config->dpms_state = DPMS_ON; 14 config->handler_context.output_config->dpms_state = DPMS_ON;
14 } else if (strcmp(*argv, "off") == 0) {
15 config->handler_context.output_config->dpms_state = DPMS_OFF;
16 } else { 15 } else {
17 return cmd_results_new(CMD_INVALID, "output", 16 config->handler_context.output_config->dpms_state = DPMS_OFF;
18 "Invalid dpms state, valid states are on/off.");
19 } 17 }
20 18
21 config->handler_context.leftovers.argc = argc - 1; 19 config->handler_context.leftovers.argc = argc - 1;
diff --git a/sway/commands/reload.c b/sway/commands/reload.c
index cea6a94b..5c1b19b4 100644
--- a/sway/commands/reload.c
+++ b/sway/commands/reload.c
@@ -1,17 +1,46 @@
1#define _XOPEN_SOURCE 500
2#include <string.h>
1#include "sway/commands.h" 3#include "sway/commands.h"
2#include "sway/config.h" 4#include "sway/config.h"
5#include "sway/ipc-server.h"
3#include "sway/tree/arrange.h" 6#include "sway/tree/arrange.h"
7#include "list.h"
4 8
5struct cmd_results *cmd_reload(int argc, char **argv) { 9struct cmd_results *cmd_reload(int argc, char **argv) {
6 struct cmd_results *error = NULL; 10 struct cmd_results *error = NULL;
7 if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { 11 if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
8 return error; 12 return error;
9 } 13 }
14
15 // store bar ids to check against new bars for barconfig_update events
16 list_t *bar_ids = create_list();
17 for (int i = 0; i < config->bars->length; ++i) {
18 struct bar_config *bar = config->bars->items[i];
19 list_add(bar_ids, strdup(bar->id));
20 }
21
10 if (!load_main_config(config->current_config_path, true)) { 22 if (!load_main_config(config->current_config_path, true)) {
11 return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); 23 return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
12 } 24 }
25 ipc_event_workspace(NULL, NULL, "reload");
13 26
14 load_swaybars(); 27 load_swaybars();
28
29 for (int i = 0; i < config->bars->length; ++i) {
30 struct bar_config *bar = config->bars->items[i];
31 for (int j = 0; j < bar_ids->length; ++j) {
32 if (strcmp(bar->id, bar_ids->items[j]) == 0) {
33 ipc_event_barconfig_update(bar);
34 break;
35 }
36 }
37 }
38
39 for (int i = 0; i < bar_ids->length; ++i) {
40 free(bar_ids->items[i]);
41 }
42 list_free(bar_ids);
43
15 arrange_windows(&root_container); 44 arrange_windows(&root_container);
16 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 45 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
17} 46}
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c
new file mode 100644
index 00000000..01a91d65
--- /dev/null
+++ b/sway/commands/scratchpad.c
@@ -0,0 +1,44 @@
1#include "log.h"
2#include "sway/commands.h"
3#include "sway/config.h"
4#include "sway/scratchpad.h"
5#include "sway/tree/container.h"
6
7struct cmd_results *cmd_scratchpad(int argc, char **argv) {
8 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1))) {
10 return error;
11 }
12 if (strcmp(argv[0], "show") != 0) {
13 return cmd_results_new(CMD_INVALID, "scratchpad",
14 "Expected 'scratchpad show'");
15 }
16 if (!root_container.sway_root->scratchpad->length) {
17 return cmd_results_new(CMD_INVALID, "scratchpad",
18 "Scratchpad is empty");
19 }
20
21 if (config->handler_context.using_criteria) {
22 struct sway_container *con = config->handler_context.current_container;
23
24 // If the container is in a floating split container,
25 // operate on the split container instead of the child.
26 if (container_is_floating_or_child(con)) {
27 while (con->parent->layout != L_FLOATING) {
28 con = con->parent;
29 }
30 }
31
32 // If using criteria, this command is executed for every container which
33 // matches the criteria. If this container isn't in the scratchpad,
34 // we'll just silently return a success.
35 if (!con->scratchpad) {
36 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
37 }
38 scratchpad_toggle_container(con);
39 } else {
40 scratchpad_toggle_auto();
41 }
42
43 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
44}
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c
index c7fdc538..434a0e27 100644
--- a/sway/commands/show_marks.c
+++ b/sway/commands/show_marks.c
@@ -7,6 +7,7 @@
7#include "list.h" 7#include "list.h"
8#include "log.h" 8#include "log.h"
9#include "stringop.h" 9#include "stringop.h"
10#include "util.h"
10 11
11static void rebuild_marks_iterator(struct sway_container *con, void *data) { 12static void rebuild_marks_iterator(struct sway_container *con, void *data) {
12 if (con->type == C_VIEW) { 13 if (con->type == C_VIEW) {
@@ -20,14 +21,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) {
20 return error; 21 return error;
21 } 22 }
22 23
23 if (strcmp(*argv, "yes") == 0) { 24 config->show_marks = parse_boolean(argv[0], config->show_marks);
24 config->show_marks = true;
25 } else if (strcmp(*argv, "no") == 0) {
26 config->show_marks = false;
27 } else {
28 return cmd_results_new(CMD_INVALID, "show_marks",
29 "Expected 'show_marks <yes|no>'");
30 }
31 25
32 if (config->show_marks) { 26 if (config->show_marks) {
33 container_for_each_descendant_dfs(&root_container, 27 container_for_each_descendant_dfs(&root_container,
diff --git a/sway/commands/split.c b/sway/commands/split.c
index 313799da..a8eddf54 100644
--- a/sway/commands/split.c
+++ b/sway/commands/split.c
@@ -10,10 +10,6 @@
10 10
11static struct cmd_results *do_split(int layout) { 11static struct cmd_results *do_split(int layout) {
12 struct sway_container *con = config->handler_context.current_container; 12 struct sway_container *con = config->handler_context.current_container;
13 if (container_is_floating(con)) {
14 return cmd_results_new(CMD_FAILURE, "split",
15 "Can't split a floating view");
16 }
17 struct sway_container *parent = container_split(con, layout); 13 struct sway_container *parent = container_split(con, layout);
18 container_create_notify(parent); 14 container_create_notify(parent);
19 arrange_windows(parent->parent); 15 arrange_windows(parent->parent);
diff --git a/sway/commands/swap.c b/sway/commands/swap.c
index 2fc88308..4e3a9cce 100644
--- a/sway/commands/swap.c
+++ b/sway/commands/swap.c
@@ -1,5 +1,6 @@
1#include <strings.h> 1#include <strings.h>
2#include <wlr/util/log.h> 2#include <wlr/util/log.h>
3#include "config.h"
3#include "sway/commands.h" 4#include "sway/commands.h"
4#include "sway/tree/arrange.h" 5#include "sway/tree/arrange.h"
5#include "sway/tree/layout.h" 6#include "sway/tree/layout.h"
@@ -14,10 +15,14 @@ static bool test_con_id(struct sway_container *container, void *con_id) {
14} 15}
15 16
16static bool test_id(struct sway_container *container, void *id) { 17static bool test_id(struct sway_container *container, void *id) {
18#ifdef HAVE_XWAYLAND
17 xcb_window_t *wid = id; 19 xcb_window_t *wid = id;
18 return (container->type == C_VIEW 20 return (container->type == C_VIEW
19 && container->sway_view->type == SWAY_VIEW_XWAYLAND 21 && container->sway_view->type == SWAY_VIEW_XWAYLAND
20 && container->sway_view->wlr_xwayland_surface->window_id == *wid); 22 && container->sway_view->wlr_xwayland_surface->window_id == *wid);
23#else
24 return false;
25#endif
21} 26}
22 27
23static bool test_mark(struct sway_container *container, void *mark) { 28static bool test_mark(struct sway_container *container, void *mark) {
@@ -43,8 +48,10 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
43 48
44 char *value = join_args(argv + 3, argc - 3); 49 char *value = join_args(argv + 3, argc - 3);
45 if (strcasecmp(argv[2], "id") == 0) { 50 if (strcasecmp(argv[2], "id") == 0) {
51#ifdef HAVE_XWAYLAND
46 xcb_window_t id = strtol(value, NULL, 0); 52 xcb_window_t id = strtol(value, NULL, 0);
47 other = container_find(&root_container, test_id, (void *)&id); 53 other = container_find(&root_container, test_id, (void *)&id);
54#endif
48 } else if (strcasecmp(argv[2], "con_id") == 0) { 55 } else if (strcasecmp(argv[2], "con_id") == 0) {
49 size_t con_id = atoi(value); 56 size_t con_id = atoi(value);
50 other = container_find(&root_container, test_con_id, (void *)con_id); 57 other = container_find(&root_container, test_con_id, (void *)con_id);
diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c
index d199858a..51c497c4 100644
--- a/sway/commands/urgent.c
+++ b/sway/commands/urgent.c
@@ -5,6 +5,7 @@
5#include "sway/tree/container.h" 5#include "sway/tree/container.h"
6#include "sway/tree/view.h" 6#include "sway/tree/view.h"
7#include "sway/tree/layout.h" 7#include "sway/tree/layout.h"
8#include "util.h"
8 9
9struct cmd_results *cmd_urgent(int argc, char **argv) { 10struct cmd_results *cmd_urgent(int argc, char **argv) {
10 struct cmd_results *error = NULL; 11 struct cmd_results *error = NULL;
@@ -19,17 +20,12 @@ struct cmd_results *cmd_urgent(int argc, char **argv) {
19 } 20 }
20 struct sway_view *view = container->sway_view; 21 struct sway_view *view = container->sway_view;
21 22
22 if (strcmp(argv[0], "enable") == 0) { 23 if (strcmp(argv[0], "allow") == 0) {
23 view_set_urgent(view, true);
24 } else if (strcmp(argv[0], "disable") == 0) {
25 view_set_urgent(view, false);
26 } else if (strcmp(argv[0], "allow") == 0) {
27 view->allow_request_urgent = true; 24 view->allow_request_urgent = true;
28 } else if (strcmp(argv[0], "deny") == 0) { 25 } else if (strcmp(argv[0], "deny") == 0) {
29 view->allow_request_urgent = false; 26 view->allow_request_urgent = false;
30 } else { 27 } else {
31 return cmd_results_new(CMD_INVALID, "urgent", 28 view_set_urgent(view, parse_boolean(argv[0], view_is_urgent(view)));
32 "Expected 'urgent <enable|disable|allow|deny>'");
33 } 29 }
34 30
35 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 31 return cmd_results_new(CMD_SUCCESS, NULL, NULL);