aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2015-09-13 19:46:16 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2015-09-13 19:46:16 -0400
commite505abfe75923d06098f6230e5a7ba39c091d3ce (patch)
treefc90bdf0afed21d725f6ee7a9245e397e1577517
parentMerge pull request #179 from taiyu-len/master (diff)
downloadsway-e505abfe75923d06098f6230e5a7ba39c091d3ce.tar.gz
sway-e505abfe75923d06098f6230e5a7ba39c091d3ce.tar.zst
sway-e505abfe75923d06098f6230e5a7ba39c091d3ce.zip
Revert "new_workspace null behavior + testmap functions + regex"
This reverts commit e1d18e42a8f3a597b9bf5f1bb2ab6c346e4e7983. Fixes #180 cc @taiyu-len
-rw-r--r--include/commands.h16
-rw-r--r--include/config.h4
-rw-r--r--include/container.h139
-rw-r--r--include/stringop.h2
-rw-r--r--include/workspace.h16
-rw-r--r--sway/commands.c167
-rw-r--r--sway/config.c25
-rw-r--r--sway/container.c415
-rw-r--r--sway/handlers.c12
-rw-r--r--sway/ipc.c4
-rw-r--r--sway/stringop.c2
-rw-r--r--sway/workspace.c149
12 files changed, 370 insertions, 581 deletions
diff --git a/include/commands.h b/include/commands.h
index 69ab1380..5c87be51 100644
--- a/include/commands.h
+++ b/include/commands.h
@@ -3,21 +3,19 @@
3#include <stdbool.h> 3#include <stdbool.h>
4#include "config.h" 4#include "config.h"
5 5
6typedef enum cmd_status {
7 CMD_SUCCESS,
8 CMD_FAILURE,
9 CMD_DEFER,
10} sway_cmd(char *criteria, int argc, char **argv);
11
12struct cmd_handler { 6struct cmd_handler {
13 const char*command; 7 char *command;
14 sway_cmd *handle; 8 enum cmd_status {
9 CMD_SUCCESS,
10 CMD_FAILURE,
11 CMD_DEFER,
12 } (*handle)(int argc, char **argv);
15}; 13};
16 14
17enum cmd_status handle_command(char *command); 15enum cmd_status handle_command(char *command);
18// Handles commands during config 16// Handles commands during config
19enum cmd_status config_command(char *command); 17enum cmd_status config_command(char *command);
20 18
21void remove_view_from_scratchpad(swayc_t *view); 19void remove_view_from_scratchpad();
22 20
23#endif 21#endif
diff --git a/include/config.h b/include/config.h
index 04db3e5c..676218c8 100644
--- a/include/config.h
+++ b/include/config.h
@@ -63,10 +63,6 @@ bool load_config(const char *file);
63bool read_config(FILE *file, bool is_active); 63bool read_config(FILE *file, bool is_active);
64char *do_var_replacement(char *str); 64char *do_var_replacement(char *str);
65 65
66// Find workspace_output from config by workspace or output name
67struct workspace_output *wsop_find_workspace(const char *);
68struct workspace_output *wsop_find_output(const char *);
69
70extern struct sway_config *config; 66extern struct sway_config *config;
71 67
72#endif 68#endif
diff --git a/include/container.h b/include/container.h
index b164af95..ae9a9fc5 100644
--- a/include/container.h
+++ b/include/container.h
@@ -2,25 +2,29 @@
2#define _SWAY_CONTAINER_H 2#define _SWAY_CONTAINER_H
3#include <wlc/wlc.h> 3#include <wlc/wlc.h>
4typedef struct sway_container swayc_t; 4typedef struct sway_container swayc_t;
5
5#include "layout.h" 6#include "layout.h"
6 7
7enum swayc_types { 8enum swayc_types{
8 C_ROOT = 1 << 0, 9 C_ROOT,
9 C_OUTPUT = 1 << 1, 10 C_OUTPUT,
10 C_WORKSPACE = 1 << 2, 11 C_WORKSPACE,
11 C_CONTAINER = 1 << 3, 12 C_CONTAINER,
12 C_VIEW = 1 << 4, 13 C_VIEW,
13 C_TYPES = 5, 14 // Keep last
15 C_TYPES,
14}; 16};
15 17
16enum swayc_layouts { 18
17 L_NONE = 1 << 0, 19enum swayc_layouts{
18 L_HORIZ = 1 << 1, 20 L_NONE,
19 L_VERT = 1 << 2, 21 L_HORIZ,
20 L_STACKED = 1 << 3, 22 L_VERT,
21 L_TABBED = 1 << 4, 23 L_STACKED,
22 L_FLOATING = 1 << 5, 24 L_TABBED,
23 L_LAYOUTS = 6, 25 L_FLOATING,
26 // Keep last
27 L_LAYOUTS,
24}; 28};
25 29
26struct sway_container { 30struct sway_container {
@@ -31,16 +35,13 @@ struct sway_container {
31 35
32 // Not including borders or margins 36 // Not including borders or margins
33 double width, height; 37 double width, height;
34 double x, y;
35 38
36 // Used for setting floating geometry 39 // Used for setting floating geometry
37 int desired_width, desired_height; 40 int desired_width, desired_height;
38 41
39 enum visibility_mask { 42 double x, y;
40 INVISIBLE = false,
41 VISIBLE = true,
42 } visible;
43 43
44 bool visible;
44 bool is_floating; 45 bool is_floating;
45 bool is_focused; 46 bool is_focused;
46 47
@@ -55,120 +56,70 @@ struct sway_container {
55 struct sway_container *focused; 56 struct sway_container *focused;
56}; 57};
57 58
58// swayc Creation 59enum visibility_mask {
60 VISIBLE = true
61} visible;
59 62
60/* Creates and returns new, or an already created output. 63// Container Creation
61 * If it creates a new output, it also creates a workspace using
62 * `new_workspace(outputname, NULL);` */
63swayc_t *new_output(wlc_handle handle);
64 64
65/* Creates workspace with given name, under given output. 65swayc_t *new_output(wlc_handle handle);
66 * If workspace with that name already exists, returns that workspace
67 * If name is NULL, it will choose a name automatically.
68 * If output is NULL, it will choose an output automatically. */
69swayc_t *new_workspace(swayc_t *output, const char *name); 66swayc_t *new_workspace(swayc_t *output, const char *name);
70
71// Creates container Around child (parent child) -> (parent (container child)) 67// Creates container Around child (parent child) -> (parent (container child))
72swayc_t *new_container(swayc_t *child, enum swayc_layouts layout); 68swayc_t *new_container(swayc_t *child, enum swayc_layouts layout);
73
74// Creates view as a sibling of current focused container, or as child of a workspace 69// Creates view as a sibling of current focused container, or as child of a workspace
75swayc_t *new_view(swayc_t *sibling, wlc_handle handle); 70swayc_t *new_view(swayc_t *sibling, wlc_handle handle);
76
77// Creates view as a new floating view which is in the active workspace 71// Creates view as a new floating view which is in the active workspace
78swayc_t *new_floating_view(wlc_handle handle); 72swayc_t *new_floating_view(wlc_handle handle);
79 73
80// Container Destroying 74// Container Destroying
81// Destroys output and moves workspaces to another output
82swayc_t *destroy_output(swayc_t *output);
83 75
76swayc_t *destroy_output(swayc_t *output);
84// Destroys workspace if empty and returns parent pointer, else returns NULL 77// Destroys workspace if empty and returns parent pointer, else returns NULL
85swayc_t *destroy_workspace(swayc_t *workspace); 78swayc_t *destroy_workspace(swayc_t *workspace);
86
87// Destroyes container and all parent container if they are empty, returns 79// Destroyes container and all parent container if they are empty, returns
88// topmost non-empty parent. returns NULL otherwise 80// topmost non-empty parent. returns NULL otherwise
89swayc_t *destroy_container(swayc_t *container); 81swayc_t *destroy_container(swayc_t *container);
90
91// Destroys view and all empty parent containers. return topmost non-empty 82// Destroys view and all empty parent containers. return topmost non-empty
92// parent 83// parent
93swayc_t *destroy_view(swayc_t *view); 84swayc_t *destroy_view(swayc_t *view);
94 85
95// Container Mapping and testing functions 86// Container Lookup
96typedef bool swayc_test_func(swayc_t *view, void *data);
97typedef void swayc_map_func(swayc_t *view, void *data);
98
99// Returns the first swayc that matches test()
100swayc_t *swayc_by_test_r(swayc_t *root, swayc_test_func test, void *data);
101swayc_t *swayc_by_test(swayc_test_func test, void *data);
102
103// Calls func for all children.
104void swayc_map_r(swayc_t *root, swayc_map_func func, void *data);
105void swayc_map(swayc_map_func func, void *data);
106
107
108// Call func on container if test passes
109void swayc_map_by_test_r(swayc_t *root,
110 swayc_map_func func, swayc_test_func test,
111 void *funcdata, void *testdata);
112void swayc_map_by_test(
113 swayc_map_func func, swayc_test_func test,
114 void *funcdata, void *testdata);
115
116// Map functions
117swayc_map_func set_gaps;
118swayc_map_func add_gaps;
119
120// Test functions
121// generic swayc tests
122swayc_test_func test_name;
123swayc_test_func test_name_regex;
124swayc_test_func test_layout;
125swayc_test_func test_type;
126swayc_test_func test_visibility;
127swayc_test_func test_handle;
128
129// C_VIEW tests
130// See wlc_view_*_bit enums
131swayc_test_func test_view_state;
132swayc_test_func test_view_type;
133swayc_test_func test_view_title;
134swayc_test_func test_view_class;
135swayc_test_func test_view_appid;
136swayc_test_func test_view_title_regex;
137swayc_test_func test_view_class_regex;
138swayc_test_func test_view_appid_regex;
139
140// functions for test_*_regex
141void *compile_regex(const char *regex);
142void free_regex(void *);
143
144// these take a NULL terminated array of test_list struct.
145struct test_list { swayc_test_func *test; void *data ; };
146swayc_test_func test_and;
147swayc_test_func test_or;
148 87
88swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
149swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types); 89swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types);
150swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts); 90swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts);
151// Follow focused until type/layout 91// Follow focused until type/layout
152swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types); 92swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types);
153swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts); 93swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts);
154 94
95
96swayc_t *swayc_by_handle(wlc_handle handle);
97swayc_t *swayc_by_name(const char *name);
155swayc_t *swayc_active_output(void); 98swayc_t *swayc_active_output(void);
156swayc_t *swayc_active_workspace(void); 99swayc_t *swayc_active_workspace(void);
157swayc_t *swayc_active_workspace_for(swayc_t *view); 100swayc_t *swayc_active_workspace_for(swayc_t *view);
158 101
159// Container information 102// Container information
160// if `parent` is the parent of `child` 103
104bool swayc_is_fullscreen(swayc_t *view);
105bool swayc_is_active(swayc_t *view);
106// Is `parent` the parent of `child`
161bool swayc_is_parent_of(swayc_t *parent, swayc_t *child); 107bool swayc_is_parent_of(swayc_t *parent, swayc_t *child);
162// If `child` is a child of `parent` 108// Is `child` a child of `parent`
163bool swayc_is_child_of(swayc_t *child, swayc_t *parent); 109bool swayc_is_child_of(swayc_t *child, swayc_t *parent);
164// Return gap of specified container 110// Return gap of specified container
165int swayc_gap(swayc_t *container); 111int swayc_gap(swayc_t *container);
166 112
167bool swayc_is_fullscreen(swayc_t *view); 113// Mapping functions
168bool swayc_is_active(swayc_t *view); 114
115void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
169 116
117// Mappings
118void set_view_visibility(swayc_t *view, void *data);
119// Set or add to gaps
120void set_gaps(swayc_t *view, void *amount);
121void add_gaps(swayc_t *view, void *amount);
170 122
171// Specialized mapping functions
172void update_visibility(swayc_t *container); 123void update_visibility(swayc_t *container);
173 124
174#endif 125#endif
diff --git a/include/stringop.h b/include/stringop.h
index 6e80e729..dde50f13 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -19,7 +19,7 @@ void free_argv(int argc, char **argv);
19char *code_strchr(const char *string, char delimiter); 19char *code_strchr(const char *string, char delimiter);
20char *code_strstr(const char *haystack, const char *needle); 20char *code_strstr(const char *haystack, const char *needle);
21int unescape_string(char *string); 21int unescape_string(char *string);
22char *join_args(int argc, char **argv); 22char *join_args(char **argv, int argc);
23char *join_list(list_t *list, char *separator); 23char *join_list(list_t *list, char *separator);
24 24
25char *strdup(const char *); 25char *strdup(const char *);
diff --git a/include/workspace.h b/include/workspace.h
index 3a63ea38..7343b055 100644
--- a/include/workspace.h
+++ b/include/workspace.h
@@ -7,17 +7,13 @@
7 7
8extern char *prev_workspace_name; 8extern char *prev_workspace_name;
9 9
10// Search for available workspace name on output from config 10char *workspace_next_name(void);
11const char *workspace_output_open_name(swayc_t *output); 11swayc_t *workspace_create(const char*);
12// Search for any available workspace name
13const char *workspace_next_name(void);
14
15
16swayc_t *workspace_by_name(const char*); 12swayc_t *workspace_by_name(const char*);
17void workspace_switch(swayc_t*); 13void workspace_switch(swayc_t*);
18swayc_t *workspace_output_next(void); 14swayc_t *workspace_output_next();
19swayc_t *workspace_next(void); 15swayc_t *workspace_next();
20swayc_t *workspace_output_prev(void); 16swayc_t *workspace_output_prev();
21swayc_t *workspace_prev(void); 17swayc_t *workspace_prev();
22 18
23#endif 19#endif
diff --git a/sway/commands.c b/sway/commands.c
index 3ed0c8db..e79746ae 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -21,35 +21,6 @@
21swayc_t *sp_view; 21swayc_t *sp_view;
22int sp_index = 0; 22int sp_index = 0;
23 23
24// Commands
25static sway_cmd cmd_bindsym;
26static sway_cmd cmd_orientation;
27static sway_cmd cmd_exec;
28static sway_cmd cmd_exec_always;
29static sway_cmd cmd_exit;
30static sway_cmd cmd_floating;
31static sway_cmd cmd_floating_mod;
32static sway_cmd cmd_focus;
33static sway_cmd cmd_focus_follows_mouse;
34static sway_cmd cmd_for_window;
35static sway_cmd cmd_fullscreen;
36static sway_cmd cmd_gaps;
37static sway_cmd cmd_kill;
38static sway_cmd cmd_layout;
39static sway_cmd cmd_log_colors;
40static sway_cmd cmd_mode;
41static sway_cmd cmd_move;
42static sway_cmd cmd_output;
43static sway_cmd cmd_reload;
44static sway_cmd cmd_resize;
45static sway_cmd cmd_scratchpad;
46static sway_cmd cmd_set;
47static sway_cmd cmd_split;
48static sway_cmd cmd_splith;
49static sway_cmd cmd_splitv;
50static sway_cmd cmd_workspace;
51static sway_cmd cmd_ws_auto_back_and_forth;
52
53static struct modifier_key { 24static struct modifier_key {
54 char *name; 25 char *name;
55 uint32_t mod; 26 uint32_t mod;
@@ -123,7 +94,7 @@ static int bindsym_sort(const void *_lbind, const void *_rbind) {
123 return (rbind->keys->length + rmod) - (lbind->keys->length + lmod); 94 return (rbind->keys->length + rmod) - (lbind->keys->length + lmod);
124} 95}
125 96
126enum cmd_status cmd_bindsym(char *criteria, int argc, char **argv) { 97static enum cmd_status cmd_bindsym(int argc, char **argv) {
127 if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1) 98 if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)
128 || !config->reading) { 99 || !config->reading) {
129 return CMD_FAILURE; 100 return CMD_FAILURE;
@@ -132,7 +103,7 @@ enum cmd_status cmd_bindsym(char *criteria, int argc, char **argv) {
132 struct sway_binding *binding = malloc(sizeof(struct sway_binding)); 103 struct sway_binding *binding = malloc(sizeof(struct sway_binding));
133 binding->keys = create_list(); 104 binding->keys = create_list();
134 binding->modifiers = 0; 105 binding->modifiers = 0;
135 binding->command = join_args(argc - 1, argv + 1); 106 binding->command = join_args(argv + 1, argc - 1);
136 107
137 list_t *split = split_string(argv[0], "+"); 108 list_t *split = split_string(argv[0], "+");
138 int i; 109 int i;
@@ -173,7 +144,7 @@ enum cmd_status cmd_bindsym(char *criteria, int argc, char **argv) {
173 return CMD_SUCCESS; 144 return CMD_SUCCESS;
174} 145}
175 146
176enum cmd_status cmd_exec_always(char *criteria, int argc, char **argv) { 147static enum cmd_status cmd_exec_always(int argc, char **argv) {
177 if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { 148 if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) {
178 return CMD_FAILURE; 149 return CMD_FAILURE;
179 } 150 }
@@ -189,7 +160,7 @@ enum cmd_status cmd_exec_always(char *criteria, int argc, char **argv) {
189 } 160 }
190 /* Child process */ 161 /* Child process */
191 if (pid == 0) { 162 if (pid == 0) {
192 char *args = join_args(argc, argv); 163 char *args = join_args(argv, argc);
193 sway_log(L_DEBUG, "Executing %s", args); 164 sway_log(L_DEBUG, "Executing %s", args);
194 execl("/bin/sh", "sh", "-c", args, (char *)NULL); 165 execl("/bin/sh", "sh", "-c", args, (char *)NULL);
195 /* Execl doesnt return unless failure */ 166 /* Execl doesnt return unless failure */
@@ -201,17 +172,17 @@ enum cmd_status cmd_exec_always(char *criteria, int argc, char **argv) {
201 return CMD_SUCCESS; 172 return CMD_SUCCESS;
202} 173}
203 174
204enum cmd_status cmd_exec(char *criteria, int argc, char **argv) { 175static enum cmd_status cmd_exec(int argc, char **argv) {
205 if (!config->active) { 176 if (!config->active) {
206 return CMD_DEFER; 177 return CMD_DEFER;
207 } 178 }
208 if (config->reloading) { 179 if (config->reloading) {
209 char *args = join_args(argc, argv); 180 char *args = join_args(argv, argc);
210 sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); 181 sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
211 free(args); 182 free(args);
212 return CMD_SUCCESS; 183 return CMD_SUCCESS;
213 } 184 }
214 return cmd_exec_always(criteria, argc, argv); 185 return cmd_exec_always(argc, argv);
215} 186}
216 187
217static void kill_views(swayc_t *container, void *data) { 188static void kill_views(swayc_t *container, void *data) {
@@ -220,19 +191,18 @@ static void kill_views(swayc_t *container, void *data) {
220 } 191 }
221} 192}
222 193
223enum cmd_status cmd_exit(char *criteria, int argc, char **argv) { 194static enum cmd_status cmd_exit(int argc, char **argv) {
224 (void) argv;
225 if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0) 195 if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)
226 || config->reading || !config->active) { 196 || config->reading || !config->active) {
227 return CMD_FAILURE; 197 return CMD_FAILURE;
228 } 198 }
229 // Close all views 199 // Close all views
230 swayc_map(kill_views, NULL); 200 container_map(&root_container, kill_views, NULL);
231 sway_terminate(); 201 sway_terminate();
232 return CMD_SUCCESS; 202 return CMD_SUCCESS;
233} 203}
234 204
235enum cmd_status cmd_floating(char *criteria, int argc, char **argv) { 205static enum cmd_status cmd_floating(int argc, char **argv) {
236 if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1) 206 if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)
237 || config->reading || !config->active) { 207 || config->reading || !config->active) {
238 return CMD_FAILURE; 208 return CMD_FAILURE;
@@ -294,7 +264,7 @@ enum cmd_status cmd_floating(char *criteria, int argc, char **argv) {
294 return CMD_SUCCESS; 264 return CMD_SUCCESS;
295} 265}
296 266
297enum cmd_status cmd_floating_mod(char *criteria, int argc, char **argv) { 267static enum cmd_status cmd_floating_mod(int argc, char **argv) {
298 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1) 268 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)
299 || !config->reading) { 269 || !config->reading) {
300 return CMD_FAILURE; 270 return CMD_FAILURE;
@@ -319,7 +289,7 @@ enum cmd_status cmd_floating_mod(char *criteria, int argc, char **argv) {
319 return CMD_SUCCESS; 289 return CMD_SUCCESS;
320} 290}
321 291
322enum cmd_status cmd_focus(char *criteria, int argc, char **argv) { 292static enum cmd_status cmd_focus(int argc, char **argv) {
323 static int floating_toggled_index = 0; 293 static int floating_toggled_index = 0;
324 static int tiled_toggled_index = 0; 294 static int tiled_toggled_index = 0;
325 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1) 295 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)
@@ -377,7 +347,7 @@ enum cmd_status cmd_focus(char *criteria, int argc, char **argv) {
377 return CMD_SUCCESS; 347 return CMD_SUCCESS;
378} 348}
379 349
380enum cmd_status cmd_focus_follows_mouse(char *criteria, int argc, char **argv) { 350static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
381 if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) { 351 if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) {
382 return CMD_FAILURE; 352 return CMD_FAILURE;
383 } 353 }
@@ -386,21 +356,6 @@ enum cmd_status cmd_focus_follows_mouse(char *criteria, int argc, char **argv) {
386 return CMD_SUCCESS; 356 return CMD_SUCCESS;
387} 357}
388 358
389static void debug_for_window(swayc_t *view, void *data) {
390 layout_log(view, 0);
391}
392
393enum cmd_status cmd_for_window(char *criteria, int argc, char **argv) {
394 if (!checkarg(argc, "for_window", EXPECTED_AT_LEAST, 1)) {
395 return CMD_FAILURE;
396 }
397 //TODO
398 void *re = compile_regex(argv[0]);
399 swayc_map_by_test(debug_for_window, test_view_title_regex, NULL, re);
400 free_regex(re);
401 return CMD_FAILURE;
402}
403
404static void hide_view_in_scratchpad(swayc_t *sp_view) { 359static void hide_view_in_scratchpad(swayc_t *sp_view) {
405 if(sp_view == NULL) { 360 if(sp_view == NULL) {
406 return; 361 return;
@@ -417,7 +372,7 @@ static void hide_view_in_scratchpad(swayc_t *sp_view) {
417 set_focused_container(container_under_pointer()); 372 set_focused_container(container_under_pointer());
418} 373}
419 374
420enum cmd_status cmd_mode(char *criteria, int argc, char **argv) { 375static enum cmd_status cmd_mode(int argc, char **argv) {
421 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { 376 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
422 return CMD_FAILURE; 377 return CMD_FAILURE;
423 } 378 }
@@ -426,7 +381,7 @@ enum cmd_status cmd_mode(char *criteria, int argc, char **argv) {
426 return CMD_FAILURE; 381 return CMD_FAILURE;
427 } 382 }
428 383
429 char *mode_name = join_args(argc - mode_make, argv); 384 char *mode_name = join_args(argv, argc - mode_make);
430 struct sway_mode *mode = NULL; 385 struct sway_mode *mode = NULL;
431 // Find mode 386 // Find mode
432 int i, len = config->modes->length; 387 int i, len = config->modes->length;
@@ -456,7 +411,7 @@ enum cmd_status cmd_mode(char *criteria, int argc, char **argv) {
456 return CMD_SUCCESS; 411 return CMD_SUCCESS;
457} 412}
458 413
459enum cmd_status cmd_move(char *criteria, int argc, char **argv) { 414static enum cmd_status cmd_move(int argc, char **argv) {
460 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1) 415 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)
461 || config->reading || !config->active) { 416 || config->reading || !config->active) {
462 return CMD_FAILURE; 417 return CMD_FAILURE;
@@ -489,7 +444,11 @@ enum cmd_status cmd_move(char *criteria, int argc, char **argv) {
489 // move "container to workspace number x" 444 // move "container to workspace number x"
490 ws_name = argv[4]; 445 ws_name = argv[4];
491 } 446 }
492 swayc_t *ws = new_workspace(NULL, ws_name); 447
448 swayc_t *ws = workspace_by_name(ws_name);
449 if (ws == NULL) {
450 ws = workspace_create(ws_name);
451 }
493 move_container_to(view, get_focused_container(ws)); 452 move_container_to(view, get_focused_container(ws));
494 } else if (strcasecmp(argv[0], "scratchpad") == 0) { 453 } else if (strcasecmp(argv[0], "scratchpad") == 0) {
495 if (view->type != C_CONTAINER && view->type != C_VIEW) { 454 if (view->type != C_CONTAINER && view->type != C_VIEW) {
@@ -523,7 +482,7 @@ enum cmd_status cmd_move(char *criteria, int argc, char **argv) {
523 return CMD_SUCCESS; 482 return CMD_SUCCESS;
524} 483}
525 484
526enum cmd_status cmd_orientation(char *criteria, int argc, char **argv) { 485static enum cmd_status cmd_orientation(int argc, char **argv) {
527 if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1) 486 if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)
528 || !config->reading) { 487 || !config->reading) {
529 return CMD_FAILURE; 488 return CMD_FAILURE;
@@ -540,7 +499,7 @@ enum cmd_status cmd_orientation(char *criteria, int argc, char **argv) {
540 return CMD_SUCCESS; 499 return CMD_SUCCESS;
541} 500}
542 501
543enum cmd_status cmd_output(char *criteria, int argc, char **argv) { 502static enum cmd_status cmd_output(int argc, char **argv) {
544 if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { 503 if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
545 return CMD_FAILURE; 504 return CMD_FAILURE;
546 } 505 }
@@ -605,7 +564,7 @@ enum cmd_status cmd_output(char *criteria, int argc, char **argv) {
605 return CMD_SUCCESS; 564 return CMD_SUCCESS;
606} 565}
607 566
608enum cmd_status cmd_gaps(char *criteria, int argc, char **argv) { 567static enum cmd_status cmd_gaps(int argc, char **argv) {
609 if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) { 568 if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
610 return CMD_FAILURE; 569 return CMD_FAILURE;
611 } 570 }
@@ -739,14 +698,15 @@ enum cmd_status cmd_gaps(char *criteria, int argc, char **argv) {
739 top = &root_container; 698 top = &root_container;
740 } 699 }
741 int top_gap = top->gaps; 700 int top_gap = top->gaps;
742 swayc_map_r(top, method == SET ? set_gaps : add_gaps, &amount); 701 container_map(top, method == SET ? set_gaps : add_gaps, &amount);
743 top->gaps = top_gap; 702 top->gaps = top_gap;
744 arrange_windows(top, -1, -1); 703 arrange_windows(top, -1, -1);
745 } 704 }
705
746 return CMD_SUCCESS; 706 return CMD_SUCCESS;
747} 707}
748 708
749enum cmd_status cmd_kill(char *criteria, int argc, char **argv) { 709static enum cmd_status cmd_kill(int argc, char **argv) {
750 if (config->reading || !config->active) { 710 if (config->reading || !config->active) {
751 return CMD_FAILURE; 711 return CMD_FAILURE;
752 } 712 }
@@ -755,7 +715,7 @@ enum cmd_status cmd_kill(char *criteria, int argc, char **argv) {
755 return CMD_SUCCESS; 715 return CMD_SUCCESS;
756} 716}
757 717
758enum cmd_status cmd_layout(char *criteria, int argc, char **argv) { 718static enum cmd_status cmd_layout(int argc, char **argv) {
759 if (!checkarg(argc, "layout", EXPECTED_MORE_THAN, 0) 719 if (!checkarg(argc, "layout", EXPECTED_MORE_THAN, 0)
760 || config->reading || !config->active) { 720 || config->reading || !config->active) {
761 return CMD_FAILURE; 721 return CMD_FAILURE;
@@ -781,7 +741,7 @@ enum cmd_status cmd_layout(char *criteria, int argc, char **argv) {
781 return CMD_SUCCESS; 741 return CMD_SUCCESS;
782} 742}
783 743
784enum cmd_status cmd_reload(char *criteria, int argc, char **argv) { 744static enum cmd_status cmd_reload(int argc, char **argv) {
785 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0) 745 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)
786 || config->reading 746 || config->reading
787 || !load_config(NULL)) { 747 || !load_config(NULL)) {
@@ -791,7 +751,7 @@ enum cmd_status cmd_reload(char *criteria, int argc, char **argv) {
791 return CMD_SUCCESS; 751 return CMD_SUCCESS;
792} 752}
793 753
794enum cmd_status cmd_resize(char *criteria, int argc, char **argv) { 754static enum cmd_status cmd_resize(int argc, char **argv) {
795 if (!checkarg(argc, "resize", EXPECTED_AT_LEAST, 3) 755 if (!checkarg(argc, "resize", EXPECTED_AT_LEAST, 3)
796 || config->reading || !config->active) { 756 || config->reading || !config->active) {
797 return CMD_FAILURE; 757 return CMD_FAILURE;
@@ -821,7 +781,7 @@ enum cmd_status cmd_resize(char *criteria, int argc, char **argv) {
821 return CMD_SUCCESS; 781 return CMD_SUCCESS;
822} 782}
823 783
824static swayc_t *fetch_view_from_scratchpad(void) { 784static swayc_t *fetch_view_from_scratchpad() {
825 if (sp_index >= scratchpad->length) { 785 if (sp_index >= scratchpad->length) {
826 sp_index = 0; 786 sp_index = 0;
827 } 787 }
@@ -866,7 +826,7 @@ void remove_view_from_scratchpad(swayc_t *view) {
866 } 826 }
867} 827}
868 828
869enum cmd_status cmd_scratchpad(char *criteria, int argc, char **argv) { 829static enum cmd_status cmd_scratchpad(int argc, char **argv) {
870 if (!checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1) 830 if (!checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1)
871 || config->reading || !config->active) { 831 || config->reading || !config->active) {
872 return CMD_FAILURE; 832 return CMD_FAILURE;
@@ -900,7 +860,7 @@ static int compare_set(const void *_l, const void *_r) {
900 return strlen((*r)->name) - strlen((*l)->name); 860 return strlen((*r)->name) - strlen((*l)->name);
901} 861}
902 862
903enum cmd_status cmd_set(char *criteria, int argc, char **argv) { 863static enum cmd_status cmd_set(int argc, char **argv) {
904 if (!checkarg(argc, "set", EXPECTED_AT_LEAST, 2) 864 if (!checkarg(argc, "set", EXPECTED_AT_LEAST, 2)
905 || !config->reading) { 865 || !config->reading) {
906 return CMD_FAILURE; 866 return CMD_FAILURE;
@@ -923,11 +883,11 @@ enum cmd_status cmd_set(char *criteria, int argc, char **argv) {
923 list_add(config->symbols, var); 883 list_add(config->symbols, var);
924 list_sort(config->symbols, compare_set); 884 list_sort(config->symbols, compare_set);
925 } 885 }
926 var->value = join_args(argc - 1, argv + 1); 886 var->value = join_args(argv + 1, argc - 1);
927 return CMD_SUCCESS; 887 return CMD_SUCCESS;
928} 888}
929 889
930static enum cmd_status _do_split(char *criteria, int argc, char **argv, int layout) { 890static enum cmd_status _do_split(int argc, char **argv, int layout) {
931 char *name = layout == L_VERT ? "splitv" : 891 char *name = layout == L_VERT ? "splitv" :
932 layout == L_HORIZ ? "splith" : "split"; 892 layout == L_HORIZ ? "splith" : "split";
933 if (!checkarg(argc, name, EXPECTED_EQUAL_TO, 0) 893 if (!checkarg(argc, name, EXPECTED_EQUAL_TO, 0)
@@ -959,16 +919,16 @@ static enum cmd_status _do_split(char *criteria, int argc, char **argv, int layo
959 return CMD_SUCCESS; 919 return CMD_SUCCESS;
960} 920}
961 921
962enum cmd_status cmd_split(char *criteria, int argc, char **argv) { 922static enum cmd_status cmd_split(int argc, char **argv) {
963 if (!checkarg(argc, "split", EXPECTED_EQUAL_TO, 1) 923 if (!checkarg(argc, "split", EXPECTED_EQUAL_TO, 1)
964 || config->reading || !config->active) { 924 || config->reading || !config->active) {
965 return CMD_FAILURE; 925 return CMD_FAILURE;
966 } 926 }
967 927
968 if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { 928 if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) {
969 _do_split(criteria, argc - 1, argv + 1, L_VERT); 929 _do_split(argc - 1, argv + 1, L_VERT);
970 } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) { 930 } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) {
971 _do_split(criteria, argc - 1, argv + 1, L_HORIZ); 931 _do_split(argc - 1, argv + 1, L_HORIZ);
972 } else { 932 } else {
973 sway_log(L_ERROR, "Invalid split command (expected either horiziontal or vertical)."); 933 sway_log(L_ERROR, "Invalid split command (expected either horiziontal or vertical).");
974 return CMD_FAILURE; 934 return CMD_FAILURE;
@@ -976,15 +936,15 @@ enum cmd_status cmd_split(char *criteria, int argc, char **argv) {
976 return CMD_SUCCESS; 936 return CMD_SUCCESS;
977} 937}
978 938
979enum cmd_status cmd_splitv(char *criteria, int argc, char **argv) { 939static enum cmd_status cmd_splitv(int argc, char **argv) {
980 return _do_split(criteria, argc, argv, L_VERT); 940 return _do_split(argc, argv, L_VERT);
981} 941}
982 942
983enum cmd_status cmd_splith(char *criteria, int argc, char **argv) { 943static enum cmd_status cmd_splith(int argc, char **argv) {
984 return _do_split(criteria, argc, argv, L_HORIZ); 944 return _do_split(argc, argv, L_HORIZ);
985} 945}
986 946
987enum cmd_status cmd_log_colors(char *criteria, int argc, char **argv) { 947static enum cmd_status cmd_log_colors(int argc, char **argv) {
988 if (!checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1) 948 if (!checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1)
989 || !config->reading) { 949 || !config->reading) {
990 return CMD_FAILURE; 950 return CMD_FAILURE;
@@ -1000,7 +960,7 @@ enum cmd_status cmd_log_colors(char *criteria, int argc, char **argv) {
1000 return CMD_SUCCESS; 960 return CMD_SUCCESS;
1001} 961}
1002 962
1003enum cmd_status cmd_fullscreen(char *criteria, int argc, char **argv) { 963static enum cmd_status cmd_fullscreen(int argc, char **argv) {
1004 if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0) 964 if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0)
1005 || config->reading || !config->active) { 965 || config->reading || !config->active) {
1006 return CMD_FAILURE; 966 return CMD_FAILURE;
@@ -1020,7 +980,7 @@ enum cmd_status cmd_fullscreen(char *criteria, int argc, char **argv) {
1020 return CMD_SUCCESS; 980 return CMD_SUCCESS;
1021} 981}
1022 982
1023enum cmd_status cmd_workspace(char *criteria, int argc, char **argv) { 983static enum cmd_status cmd_workspace(int argc, char **argv) {
1024 if (!checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1)) { 984 if (!checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1)) {
1025 return CMD_FAILURE; 985 return CMD_FAILURE;
1026 } 986 }
@@ -1029,7 +989,28 @@ enum cmd_status cmd_workspace(char *criteria, int argc, char **argv) {
1029 if (config->reading || !config->active) { 989 if (config->reading || !config->active) {
1030 return CMD_DEFER; 990 return CMD_DEFER;
1031 } 991 }
1032 workspace_switch(new_workspace(NULL, argv[0])); 992 // Handle workspace next/prev
993 swayc_t *ws = NULL;
994 if (strcasecmp(argv[0], "next") == 0) {
995 ws = workspace_next();
996 } else if (strcasecmp(argv[0], "prev") == 0) {
997 ws = workspace_prev();
998 } else if (strcasecmp(argv[0], "next_on_output") == 0) {
999 ws = workspace_output_next();
1000 } else if (strcasecmp(argv[0], "prev_on_output") == 0) {
1001 ws = workspace_output_prev();
1002 } else if (strcasecmp(argv[0], "back_and_forth") == 0) {
1003 if (prev_workspace_name) {
1004 if (!(ws = workspace_by_name(prev_workspace_name))) {
1005 ws = workspace_create(prev_workspace_name);
1006 }
1007 }
1008 } else {
1009 if (!(ws= workspace_by_name(argv[0]))) {
1010 ws = workspace_create(argv[0]);
1011 }
1012 }
1013 workspace_switch(ws);
1033 } else { 1014 } else {
1034 if (strcasecmp(argv[1], "output") == 0) { 1015 if (strcasecmp(argv[1], "output") == 0) {
1035 if (!checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 3)) { 1016 if (!checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 3)) {
@@ -1040,12 +1021,15 @@ enum cmd_status cmd_workspace(char *criteria, int argc, char **argv) {
1040 wso->workspace = strdup(argv[0]); 1021 wso->workspace = strdup(argv[0]);
1041 wso->output = strdup(argv[2]); 1022 wso->output = strdup(argv[2]);
1042 list_add(config->workspace_outputs, wso); 1023 list_add(config->workspace_outputs, wso);
1024 if (!config->reading) {
1025 // TODO: Move workspace to output. (dont do so when reloading)
1026 }
1043 } 1027 }
1044 } 1028 }
1045 return CMD_SUCCESS; 1029 return CMD_SUCCESS;
1046} 1030}
1047 1031
1048enum cmd_status cmd_ws_auto_back_and_forth(char *criteria, int argc, char **argv) { 1032static enum cmd_status cmd_ws_auto_back_and_forth(int argc, char **argv) {
1049 if (!checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1)) { 1033 if (!checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1)) {
1050 return CMD_FAILURE; 1034 return CMD_FAILURE;
1051 } 1035 }
@@ -1060,7 +1044,7 @@ enum cmd_status cmd_ws_auto_back_and_forth(char *criteria, int argc, char **argv
1060} 1044}
1061 1045
1062/* Keep alphabetized */ 1046/* Keep alphabetized */
1063static const struct cmd_handler handlers[] = { 1047static struct cmd_handler handlers[] = {
1064 { "bindsym", cmd_bindsym }, 1048 { "bindsym", cmd_bindsym },
1065 { "default_orientation", cmd_orientation }, 1049 { "default_orientation", cmd_orientation },
1066 { "exec", cmd_exec }, 1050 { "exec", cmd_exec },
@@ -1070,7 +1054,6 @@ static const struct cmd_handler handlers[] = {
1070 { "floating_modifier", cmd_floating_mod }, 1054 { "floating_modifier", cmd_floating_mod },
1071 { "focus", cmd_focus }, 1055 { "focus", cmd_focus },
1072 { "focus_follows_mouse", cmd_focus_follows_mouse }, 1056 { "focus_follows_mouse", cmd_focus_follows_mouse },
1073 { "for_window", cmd_for_window },
1074 { "fullscreen", cmd_fullscreen }, 1057 { "fullscreen", cmd_fullscreen },
1075 { "gaps", cmd_gaps }, 1058 { "gaps", cmd_gaps },
1076 { "kill", cmd_kill }, 1059 { "kill", cmd_kill },
@@ -1107,7 +1090,6 @@ static struct cmd_handler *find_handler(char *line) {
1107enum cmd_status handle_command(char *exec) { 1090enum cmd_status handle_command(char *exec) {
1108 sway_log(L_INFO, "Handling command '%s'", exec); 1091 sway_log(L_INFO, "Handling command '%s'", exec);
1109 int argc; 1092 int argc;
1110 char *criteria = NULL;
1111 char **argv = split_args(exec, &argc); 1093 char **argv = split_args(exec, &argc);
1112 enum cmd_status status = CMD_FAILURE; 1094 enum cmd_status status = CMD_FAILURE;
1113 struct cmd_handler *handler; 1095 struct cmd_handler *handler;
@@ -1115,7 +1097,7 @@ enum cmd_status handle_command(char *exec) {
1115 return status; 1097 return status;
1116 } 1098 }
1117 if ((handler = find_handler(argv[0])) == NULL 1099 if ((handler = find_handler(argv[0])) == NULL
1118 || (status = handler->handle(criteria, argc - 1, argv + 1)) != CMD_SUCCESS) { 1100 || (status = handler->handle(argc - 1, argv + 1)) != CMD_SUCCESS) {
1119 sway_log(L_ERROR, "Command failed: %s", argv[0]); 1101 sway_log(L_ERROR, "Command failed: %s", argv[0]);
1120 } 1102 }
1121 free_argv(argc, argv); 1103 free_argv(argc, argv);
@@ -1126,7 +1108,6 @@ enum cmd_status config_command(char *exec) {
1126 sway_log(L_INFO, "handling config command '%s'", exec); 1108 sway_log(L_INFO, "handling config command '%s'", exec);
1127 int argc; 1109 int argc;
1128 char **argv = split_args(exec, &argc); 1110 char **argv = split_args(exec, &argc);
1129 char *criteria = NULL;
1130 enum cmd_status status = CMD_FAILURE; 1111 enum cmd_status status = CMD_FAILURE;
1131 struct cmd_handler *handler; 1112 struct cmd_handler *handler;
1132 if (!argc) { 1113 if (!argc) {
@@ -1146,7 +1127,7 @@ enum cmd_status config_command(char *exec) {
1146 for (; i < e; ++i) { 1127 for (; i < e; ++i) {
1147 argv[i] = do_var_replacement(argv[i]); 1128 argv[i] = do_var_replacement(argv[i]);
1148 } 1129 }
1149 status = handler->handle(criteria, argc - 1, argv + 1); 1130 status = handler->handle(argc - 1, argv + 1);
1150 if (status == CMD_FAILURE) { 1131 if (status == CMD_FAILURE) {
1151 sway_log(L_ERROR, "Config load failed for line `%s'", exec); 1132 sway_log(L_ERROR, "Config load failed for line `%s'", exec);
1152 } else if (status == CMD_DEFER) { 1133 } else if (status == CMD_DEFER) {
diff --git a/sway/config.c b/sway/config.c
index da92030e..23d6ac0d 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -286,28 +286,3 @@ char *do_var_replacement(char *str) {
286 } 286 }
287 return str; 287 return str;
288} 288}
289
290struct workspace_output *wsop_find_workspace(const char *name) {
291 int i, len = config->workspace_outputs->length;
292 struct workspace_output *wsop;
293 for (i = 0; i < len; ++i) {
294 wsop = config->workspace_outputs->items[i];
295 if (strcasecmp(wsop->workspace, name) == 0) {
296 return wsop;
297 }
298 }
299 return NULL;
300}
301
302struct workspace_output *wsop_find_output(const char *name) {
303 int i, len = config->workspace_outputs->length;
304 struct workspace_output *wsop;
305 for (i = 0; i < len; ++i) {
306 wsop = config->workspace_outputs->items[i];
307 if (strcasecmp(wsop->output, name) == 0) {
308 return wsop;
309 }
310 }
311 return NULL;
312}
313
diff --git a/sway/container.c b/sway/container.c
index baf84378..ef0e6c55 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -1,7 +1,6 @@
1#include <stdlib.h> 1#include <stdlib.h>
2#include <stdbool.h> 2#include <stdbool.h>
3#include <strings.h> 3#include <strings.h>
4#include <pcre.h>
5#include "config.h" 4#include "config.h"
6#include "container.h" 5#include "container.h"
7#include "workspace.h" 6#include "workspace.h"
@@ -54,30 +53,26 @@ static void free_swayc(swayc_t *cont) {
54// New containers 53// New containers
55 54
56swayc_t *new_output(wlc_handle handle) { 55swayc_t *new_output(wlc_handle handle) {
56 const struct wlc_size *size = wlc_output_get_resolution(handle);
57 const char *name = wlc_output_get_name(handle); 57 const char *name = wlc_output_get_name(handle);
58 int i, len;
59
60 // Find current outputs to see if this already exists 58 // Find current outputs to see if this already exists
61 if (name) { 59 {
62 len = root_container.children->length; 60 int i, len = root_container.children->length;
63 for (i = 0; i < len; ++i) { 61 for (i = 0; i < len; ++i) {
64 swayc_t *op = root_container.children->items[i]; 62 swayc_t *op = root_container.children->items[i];
65 if (strcmp(op->name, name) == 0) { 63 const char *op_name = op->name;
66 sway_log(L_DEBUG, "restoring output %lu:%s", handle, op->name); 64 if (op_name && name && strcmp(op_name, name) == 0) {
65 sway_log(L_DEBUG, "restoring output %lu:%s", handle, op_name);
67 return op; 66 return op;
68 } 67 }
69 } 68 }
70 } else {
71 sway_log(L_ERROR, "Output has no given name");
72 return NULL;
73 } 69 }
74 70
75 sway_log(L_DEBUG, "Adding output %lu:%s", handle, name); 71 sway_log(L_DEBUG, "Added output %lu:%s", handle, name);
76 72
77 // Find output config
78 struct output_config *oc = NULL; 73 struct output_config *oc = NULL;
79 len = config->output_configs->length; 74 int i;
80 for (i = 0; i < len; ++i) { 75 for (i = 0; i < config->output_configs->length; ++i) {
81 oc = config->output_configs->items[i]; 76 oc = config->output_configs->items[i];
82 if (strcasecmp(name, oc->name) == 0) { 77 if (strcasecmp(name, oc->name) == 0) {
83 sway_log(L_DEBUG, "Matched output config for %s", name); 78 sway_log(L_DEBUG, "Matched output config for %s", name);
@@ -91,88 +86,77 @@ swayc_t *new_output(wlc_handle handle) {
91 } 86 }
92 87
93 swayc_t *output = new_swayc(C_OUTPUT); 88 swayc_t *output = new_swayc(C_OUTPUT);
89 if (oc && oc->width != -1 && oc->height != -1) {
90 output->width = oc->width;
91 output->height = oc->height;
92 struct wlc_size new_size = { .w = oc->width, .h = oc->height };
93 wlc_output_set_resolution(handle, &new_size);
94 } else {
95 output->width = size->w;
96 output->height = size->h;
97 }
94 output->handle = handle; 98 output->handle = handle;
95 output->name = name ? strdup(name) : NULL; 99 output->name = name ? strdup(name) : NULL;
96 100
97 if (oc) { 101 // Find position for it
98 // Set output width/height 102 if (oc && oc->x != -1 && oc->y != -1) {
99 if (oc->width > 0 && oc->height > 0) { 103 sway_log(L_DEBUG, "Set %s position to %d, %d", name, oc->x, oc->y);
100 output->width = oc->width; 104 output->x = oc->x;
101 output->height = oc->height; 105 output->y = oc->y;
102 struct wlc_size geo = { .w = oc->width, .h = oc->height}; 106 } else {
103 wlc_output_set_resolution(handle, &geo); 107 int x = 0;
104 } else { 108 for (i = 0; i < root_container.children->length; ++i) {
105 struct wlc_size geo = *wlc_output_get_resolution(handle); 109 swayc_t *c = root_container.children->items[i];
106 output->width = geo.w; 110 if (c->type == C_OUTPUT) {
107 output->height = geo.h; 111 if (c->width + c->x > x) {
108 } 112 x = c->width + c->x;
109 // find position in config or find where it should go
110 // TODO more intelligent method
111 if (oc->x > 0 && oc->y > 0) {
112 output->x = oc->x;
113 output->y = oc->y;
114 } else {
115 unsigned int x = 0;
116 len = root_container.children->length;
117 for (i = 0; i < len; ++i) {
118 swayc_t *c = root_container.children->items[i];
119 if (c->type == C_OUTPUT) {
120 unsigned int cx = c->width + c->x;
121 if (cx > x) {
122 x = cx;
123 }
124 } 113 }
125 } 114 }
126 output->x = x;
127 } 115 }
116 output->x = x;
128 } 117 }
129 // Add as child to root 118
130 add_child(&root_container, output); 119 add_child(&root_container, output);
131 120
121 // Create workspace
122 char *ws_name = NULL;
123 if (name) {
124 for (i = 0; i < config->workspace_outputs->length; ++i) {
125 struct workspace_output *wso = config->workspace_outputs->items[i];
126 if (strcasecmp(wso->output, name) == 0) {
127 sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output);
128 // Check if any other workspaces are using this name
129 if (workspace_by_name(wso->workspace)) {
130 sway_log(L_DEBUG, "But it's already taken");
131 break;
132 }
133 sway_log(L_DEBUG, "So we're going to use it");
134 ws_name = strdup(wso->workspace);
135 break;
136 }
137 }
138 }
139 if (!ws_name) {
140 ws_name = workspace_next_name();
141 }
142
132 // create and initilize default workspace 143 // create and initilize default workspace
133 swayc_t *ws = new_workspace(output, NULL); 144 swayc_t *ws = new_workspace(output, ws_name);
134 ws->is_focused = true; 145 ws->is_focused = true;
135 146
147 free(ws_name);
148
136 return output; 149 return output;
137} 150}
138 151
139swayc_t *new_workspace(swayc_t *output, const char *name) { 152swayc_t *new_workspace(swayc_t *output, const char *name) {
140 swayc_t *ws = NULL; 153 if (!ASSERT_NONNULL(output)) {
141 struct workspace_output *wsop; 154 return NULL;
142 if (name) {
143 // Find existing workspace with same name.
144 // or workspace found by special name
145 if ((ws = workspace_by_name(name))) {
146 return ws;
147 }
148 // Find matching output from config
149 if (!output) {
150 if ((wsop = wsop_find_workspace(name))) {
151 int i, len = root_container.children->length;
152 for (i = 0; i < len; ++i) {
153 swayc_t *op = root_container.children->items[i];
154 if (strcasecmp(op->name, wsop->output) == 0) {
155 output = op;
156 goto find_wsop_end;
157 }
158 }
159 }
160 // Set output to active_output if there is no output.
161 output = swayc_active_output();
162 find_wsop_end:;
163 }
164 } else {
165 // No name or output, use active_output
166 if (!output) {
167 output = swayc_active_output();
168 }
169 // search for available output name
170 if (!(name = workspace_output_open_name(output))) {
171 // otherwise just use simple next name
172 name = workspace_next_name();
173 }
174 } 155 }
156 sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle);
175 swayc_t *workspace = new_swayc(C_WORKSPACE); 157 swayc_t *workspace = new_swayc(C_WORKSPACE);
158
159 // TODO: default_layout
176 if (config->default_layout != L_NONE) { 160 if (config->default_layout != L_NONE) {
177 workspace->layout = config->default_layout; 161 workspace->layout = config->default_layout;
178 } else if (config->default_orientation != L_NONE) { 162 } else if (config->default_orientation != L_NONE) {
@@ -390,7 +374,7 @@ swayc_t *destroy_view(swayc_t *view) {
390// Container lookup 374// Container lookup
391 375
392 376
393swayc_t *swayc_by_test_r(swayc_t *container, swayc_test_func test, void *data) { 377swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) {
394 if (!container->children) { 378 if (!container->children) {
395 return NULL; 379 return NULL;
396 } 380 }
@@ -409,7 +393,7 @@ swayc_t *swayc_by_test_r(swayc_t *container, swayc_test_func test, void *data) {
409 if (test(child, data)) { 393 if (test(child, data)) {
410 return child; 394 return child;
411 } else { 395 } else {
412 swayc_t *res = swayc_by_test_r(child, test, data); 396 swayc_t *res = swayc_by_test(child, test, data);
413 if (res) { 397 if (res) {
414 return res; 398 return res;
415 } 399 }
@@ -417,193 +401,18 @@ swayc_t *swayc_by_test_r(swayc_t *container, swayc_test_func test, void *data) {
417 } 401 }
418 return NULL; 402 return NULL;
419} 403}
420swayc_t *swayc_by_test(swayc_test_func test, void *data) {
421 return swayc_by_test_r(&root_container, test, data);
422}
423
424void swayc_map_r(swayc_t *container, swayc_map_func f, void *data) {
425 if (container) {
426 f(container, data);
427 int i;
428 if (container->children) {
429 for (i = 0; i < container->children->length; ++i) {
430 swayc_t *child = container->children->items[i];
431 swayc_map_r(child, f, data);
432 }
433 }
434 if (container->floating) {
435 for (i = 0; i < container->floating->length; ++i) {
436 swayc_t *child = container->floating->items[i];
437 swayc_map_r(child, f, data);
438 }
439 }
440 }
441}
442void swayc_map(swayc_map_func f, void *data) {
443 swayc_map_r(&root_container, f, data);
444}
445
446void swayc_map_by_test_r(swayc_t *container,
447 swayc_map_func func, swayc_test_func test,
448 void *funcdata, void *testdata) {
449 if (container) {
450 if (test(container, testdata)) {
451 func(container, funcdata);
452 }
453 int i;
454 if (container->children) {
455 for (i = 0; i < container->children->length; ++i) {
456 swayc_t *child = container->children->items[i];
457 swayc_map_by_test_r(child, func, test, funcdata, testdata);
458 }
459 }
460 if (container->floating) {
461 for (i = 0; i < container->floating->length; ++i) {
462 swayc_t *child = container->floating->items[i];
463 swayc_map_by_test_r(child, func, test, funcdata, testdata);
464 }
465 }
466 }
467}
468void swayc_map_by_test(
469 swayc_map_func func, swayc_test_func test,
470 void *funcdata, void *testdata) {
471 swayc_map_by_test_r(&root_container, func, test, funcdata, testdata);
472}
473
474
475
476// Map functions
477void set_gaps(swayc_t *view, void *_data) {
478 int *data = _data;
479 if (view->type == C_WORKSPACE || view->type == C_VIEW) {
480 view->gaps = *data;
481 }
482}
483 404
484void add_gaps(swayc_t *view, void *_data) { 405static bool test_name(swayc_t *view, void *data) {
485 int *data = _data; 406 if (!view && !view->name) {
486 if (view->type == C_WORKSPACE || view->type == C_VIEW) { 407 return false;
487 if ((view->gaps += *data) < 0) {
488 view->gaps = 0;
489 }
490 } 408 }
409 return strcmp(view->name, data) == 0;
491} 410}
492 411
493// Test functions 412swayc_t *swayc_by_name(const char *name) {
494bool test_name(swayc_t *view, void *data) { 413 return swayc_by_test(&root_container, test_name, (void *)name);
495 return view->name && strcmp(view->name, data) == 0;
496} 414}
497 415
498// test_name_regex
499struct test_name_regex {
500 pcre *reg;
501 pcre_extra *regext;
502};
503
504void *compile_regex(const char *pattern) {
505 struct test_name_regex *regex = malloc(sizeof *regex);
506 const char *error;
507 int erroffset;
508 if (!(regex->reg = pcre_compile(pattern, 0, &error, &erroffset, NULL))) {
509 sway_log(L_ERROR, "Regex compilation failed:%s:%s", pattern, error);
510 free(regex);
511 return NULL;
512 }
513 regex->regext = pcre_study(regex->reg, 0, &error);
514 if (error) {
515 sway_log(L_DEBUG, "Regex study failed:%s:%s", pattern, error);
516 }
517 return regex;
518}
519
520void free_regex(void *_regex) {
521 struct test_name_regex *regex = _regex;
522 pcre_free(regex->reg);
523 pcre_free_study(regex->regext);
524 free(regex);
525}
526
527static bool exec_regex(const char *pattern, struct test_name_regex *regex) {
528 int ovector[300];
529 return 0 < pcre_exec(regex->reg, regex->regext, pattern,
530 strlen(pattern), 0, 0, ovector, 300);
531}
532
533bool test_name_regex(swayc_t *view, void *data) {
534 return view->name && exec_regex(view->name, data);
535}
536bool test_layout(swayc_t *view, void *data) {
537 return view->layout & *(enum swayc_layouts *)data;
538}
539bool test_type(swayc_t *view, void *data) {
540 return view->layout & *(enum swayc_types *)data;
541}
542bool test_visibility(swayc_t *view, void *data) {
543 return view->visible == *(bool *)data;
544}
545bool test_handle(swayc_t *view, void *data) {
546 return view->handle == *(wlc_handle *)data;
547}
548
549// C_VIEW tests
550bool test_view_state(swayc_t *view, void *data) {
551 return view->type == C_VIEW
552 && wlc_view_get_state(view->handle) & *(int *)data;
553}
554bool test_view_type(swayc_t *view, void *data) {
555 return view->type == C_VIEW
556 && wlc_view_get_type(view->handle) & *(int *)data;
557}
558bool test_view_title(swayc_t *view, void *data) {
559 return view->type == C_VIEW
560 && strcmp(view->name, data) == 0;
561}
562bool test_view_class(swayc_t *view, void *data) {
563 return view->type == C_VIEW
564 && strcmp(wlc_view_get_class(view->handle), data) == 0;
565}
566bool test_view_appid(swayc_t *view, void *data) {
567 return view->type == C_VIEW
568 && strcmp(wlc_view_get_app_id(view->handle), data) == 0;
569}
570bool test_view_title_regex(swayc_t *view, void *data) {
571 return view->type == C_VIEW
572 && exec_regex(view->name, data);
573}
574bool test_view_class_regex(swayc_t *view, void *data) {
575 return view->type == C_VIEW
576 && exec_regex(wlc_view_get_class(view->handle), data);
577}
578bool test_view_appid_regex(swayc_t *view, void *data) {
579 return view->type == C_VIEW
580 && exec_regex(wlc_view_get_app_id(view->handle), data);
581}
582
583// Fancy test combiners
584bool test_and(swayc_t *view, void *data) {
585 struct test_list *list = data;
586 while (list->test) {
587 if (!list->test(view, list->data)) {
588 return false;
589 }
590 ++list;
591 }
592 return true;
593}
594bool test_or(swayc_t *view, void *data) {
595 struct test_list *list = data;
596 while (list->test) {
597 if (list->test(view, list->data)) {
598 return true;
599 }
600 ++list;
601 }
602 return false;
603}
604
605// Focus|parent lookup
606
607swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { 416swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
608 if (!ASSERT_NONNULL(container)) { 417 if (!ASSERT_NONNULL(container)) {
609 return NULL; 418 return NULL;
@@ -656,6 +465,42 @@ swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts layout) {
656 return container; 465 return container;
657} 466}
658 467
468
469static swayc_t *_swayc_by_handle_helper(wlc_handle handle, swayc_t *parent) {
470 if (!parent || !parent->children) {
471 return NULL;
472 }
473 int i, len;
474 swayc_t **child;
475 if (parent->type == C_WORKSPACE) {
476 len = parent->floating->length;
477 child = (swayc_t **)parent->floating->items;
478 for (i = 0; i < len; ++i, ++child) {
479 if ((*child)->handle == handle) {
480 return *child;
481 }
482 }
483 }
484
485 len = parent->children->length;
486 child = (swayc_t**)parent->children->items;
487 for (i = 0; i < len; ++i, ++child) {
488 if ((*child)->handle == handle) {
489 return *child;
490 } else {
491 swayc_t *res;
492 if ((res = _swayc_by_handle_helper(handle, *child))) {
493 return res;
494 }
495 }
496 }
497 return NULL;
498}
499
500swayc_t *swayc_by_handle(wlc_handle handle) {
501 return _swayc_by_handle_helper(handle, &root_container);
502}
503
659swayc_t *swayc_active_output(void) { 504swayc_t *swayc_active_output(void) {
660 return root_container.focused; 505 return root_container.focused;
661} 506}
@@ -688,13 +533,11 @@ swayc_t *swayc_active_workspace_for(swayc_t *cont) {
688// Container information 533// Container information
689 534
690bool swayc_is_fullscreen(swayc_t *view) { 535bool swayc_is_fullscreen(swayc_t *view) {
691 return view && view->type == C_VIEW 536 return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN);
692 && wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN;
693} 537}
694 538
695bool swayc_is_active(swayc_t *view) { 539bool swayc_is_active(swayc_t *view) {
696 return view && view->type == C_VIEW 540 return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED);
697 && wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED;
698} 541}
699 542
700bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) { 543bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) {
@@ -723,6 +566,25 @@ int swayc_gap(swayc_t *container) {
723 566
724// Mapping 567// Mapping
725 568
569void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
570 if (container) {
571 f(container, data);
572 int i;
573 if (container->children) {
574 for (i = 0; i < container->children->length; ++i) {
575 swayc_t *child = container->children->items[i];
576 container_map(child, f, data);
577 }
578 }
579 if (container->floating) {
580 for (i = 0; i < container->floating->length; ++i) {
581 swayc_t *child = container->floating->items[i];
582 container_map(child, f, data);
583 }
584 }
585 }
586}
587
726void update_visibility_output(swayc_t *container, wlc_handle output) { 588void update_visibility_output(swayc_t *container, wlc_handle output) {
727 // Inherit visibility 589 // Inherit visibility
728 swayc_t *parent = container->parent; 590 swayc_t *parent = container->parent;
@@ -791,3 +653,24 @@ void update_visibility(swayc_t *container) {
791 } 653 }
792} 654}
793 655
656void set_gaps(swayc_t *view, void *_data) {
657 int *data = _data;
658 if (!ASSERT_NONNULL(view)) {
659 return;
660 }
661 if (view->type == C_WORKSPACE || view->type == C_VIEW) {
662 view->gaps = *data;
663 }
664}
665
666void add_gaps(swayc_t *view, void *_data) {
667 int *data = _data;
668 if (!ASSERT_NONNULL(view)) {
669 return;
670 }
671 if (view->type == C_WORKSPACE || view->type == C_VIEW) {
672 if ((view->gaps += *data) < 0) {
673 view->gaps = 0;
674 }
675 }
676}
diff --git a/sway/handlers.c b/sway/handlers.c
index 1a8138f8..096df53c 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -126,7 +126,7 @@ static void handle_output_destroyed(wlc_handle output) {
126 126
127static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { 127static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) {
128 sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); 128 sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h);
129 swayc_t *c = swayc_by_test(test_handle, &output); 129 swayc_t *c = swayc_by_handle(output);
130 if (!c) return; 130 if (!c) return;
131 c->width = to->w; 131 c->width = to->w;
132 c->height = to->h; 132 c->height = to->h;
@@ -134,7 +134,7 @@ static void handle_output_resolution_change(wlc_handle output, const struct wlc_
134} 134}
135 135
136static void handle_output_focused(wlc_handle output, bool focus) { 136static void handle_output_focused(wlc_handle output, bool focus) {
137 swayc_t *c = swayc_by_test(test_handle, &output); 137 swayc_t *c = swayc_by_handle(output);
138 // if for some reason this output doesnt exist, create it. 138 // if for some reason this output doesnt exist, create it.
139 if (!c) { 139 if (!c) {
140 handle_output_created(output); 140 handle_output_created(output);
@@ -152,7 +152,7 @@ static bool handle_view_created(wlc_handle handle) {
152 152
153 // Get parent container, to add view in 153 // Get parent container, to add view in
154 if (parent) { 154 if (parent) {
155 focused = swayc_by_test(test_handle, &parent); 155 focused = swayc_by_handle(parent);
156 } 156 }
157 if (!focused || focused->type == C_OUTPUT) { 157 if (!focused || focused->type == C_OUTPUT) {
158 focused = get_focused_container(&root_container); 158 focused = get_focused_container(&root_container);
@@ -221,7 +221,7 @@ static bool handle_view_created(wlc_handle handle) {
221 221
222static void handle_view_destroyed(wlc_handle handle) { 222static void handle_view_destroyed(wlc_handle handle) {
223 sway_log(L_DEBUG, "Destroying window %lu", handle); 223 sway_log(L_DEBUG, "Destroying window %lu", handle);
224 swayc_t *view = swayc_by_test(test_handle, &handle); 224 swayc_t *view = swayc_by_handle(handle);
225 225
226 // destroy views by type 226 // destroy views by type
227 switch (wlc_view_get_type(handle)) { 227 switch (wlc_view_get_type(handle)) {
@@ -258,7 +258,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo
258 // If the view is floating, then apply the geometry. 258 // If the view is floating, then apply the geometry.
259 // Otherwise save the desired width/height for the view. 259 // Otherwise save the desired width/height for the view.
260 // This will not do anything for the time being as WLC improperly sends geometry requests 260 // This will not do anything for the time being as WLC improperly sends geometry requests
261 swayc_t *view = swayc_by_test(test_handle, &handle); 261 swayc_t *view = swayc_by_handle(handle);
262 if (view) { 262 if (view) {
263 view->desired_width = geometry->size.w; 263 view->desired_width = geometry->size.w;
264 view->desired_height = geometry->size.h; 264 view->desired_height = geometry->size.h;
@@ -274,7 +274,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo
274} 274}
275 275
276static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { 276static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) {
277 swayc_t *c = swayc_by_test(test_handle, &view); 277 swayc_t *c = swayc_by_handle(view);
278 switch (state) { 278 switch (state) {
279 case WLC_BIT_FULLSCREEN: 279 case WLC_BIT_FULLSCREEN:
280 // i3 just lets it become fullscreen 280 // i3 just lets it become fullscreen
diff --git a/sway/ipc.c b/sway/ipc.c
index 86518bc6..abf2ed0c 100644
--- a/sway/ipc.c
+++ b/sway/ipc.c
@@ -207,7 +207,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
207 case IPC_GET_WORKSPACES: 207 case IPC_GET_WORKSPACES:
208 { 208 {
209 json_object *workspaces = json_object_new_array(); 209 json_object *workspaces = json_object_new_array();
210 swayc_map(ipc_get_workspaces_callback, workspaces); 210 container_map(&root_container, ipc_get_workspaces_callback, workspaces);
211 const char *json_string = json_object_to_json_string(workspaces); 211 const char *json_string = json_object_to_json_string(workspaces);
212 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); 212 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
213 json_object_put(workspaces); // free 213 json_object_put(workspaces); // free
@@ -216,7 +216,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
216 case IPC_GET_OUTPUTS: 216 case IPC_GET_OUTPUTS:
217 { 217 {
218 json_object *outputs = json_object_new_array(); 218 json_object *outputs = json_object_new_array();
219 swayc_map(ipc_get_outputs_callback, outputs); 219 container_map(&root_container, ipc_get_outputs_callback, outputs);
220 const char *json_string = json_object_to_json_string(outputs); 220 const char *json_string = json_object_to_json_string(outputs);
221 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); 221 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
222 json_object_put(outputs); // free 222 json_object_put(outputs); // free
diff --git a/sway/stringop.c b/sway/stringop.c
index 54faf74c..191e40c8 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -258,7 +258,7 @@ int unescape_string(char *string) {
258 return len - shift; 258 return len - shift;
259} 259}
260 260
261char *join_args(int argc, char **argv) { 261char *join_args(char **argv, int argc) {
262 int len = 0, i; 262 int len = 0, i;
263 for (i = 0; i < argc; ++i) { 263 for (i = 0; i < argc; ++i) {
264 len += strlen(argv[i]) + 1; 264 len += strlen(argv[i]) + 1;
diff --git a/sway/workspace.c b/sway/workspace.c
index 80141f71..658f79bc 100644
--- a/sway/workspace.c
+++ b/sway/workspace.c
@@ -15,26 +15,7 @@
15 15
16char *prev_workspace_name = NULL; 16char *prev_workspace_name = NULL;
17 17
18static swayc_t *workspace_by_name_only(const char *name); 18char *workspace_next_name(void) {
19
20const char *workspace_output_open_name(swayc_t *output) {
21 struct workspace_output *wsop;
22 int i, len = config->workspace_outputs->length;
23 // Search config for output
24 for (i = 0; i < len; ++i) {
25 wsop = config->workspace_outputs->items[i];
26 // Find matching outputs
27 if (strcasecmp(wsop->output, output->name)) {
28 // Check if workspace is available and use that name
29 if (!workspace_by_name(wsop->workspace)) {
30 return wsop->workspace;
31 }
32 }
33 }
34 return NULL;
35}
36
37const char *workspace_next_name(void) {
38 sway_log(L_DEBUG, "Workspace: Generating new name"); 19 sway_log(L_DEBUG, "Workspace: Generating new name");
39 int i; 20 int i;
40 int l = 1; 21 int l = 1;
@@ -44,29 +25,42 @@ const char *workspace_next_name(void) {
44 25
45 for (i = 0; i < mode->bindings->length; ++i) { 26 for (i = 0; i < mode->bindings->length; ++i) {
46 struct sway_binding *binding = mode->bindings->items[i]; 27 struct sway_binding *binding = mode->bindings->items[i];
47 const char *command = binding->command; 28 const char* command = binding->command;
48 const char *ws = "workspace"; 29 list_t *args = split_string(command, " ");
49 const int wslen = sizeof("workspace") - 1; 30
50 if (strncmp(ws, command, wslen) == 0) { 31 if (strcmp("workspace", args->items[0]) == 0 && args->length > 1) {
51 command += wslen; 32 sway_log(L_DEBUG, "Got valid workspace command for target: '%s'", (char *)args->items[1]);
52 // Skip whitespace 33 char* target = malloc(strlen(args->items[1]) + 1);
53 command += strspn(command, whitespace); 34 strcpy(target, args->items[1]);
54 // make sure its not a special command 35 while (*target == ' ' || *target == '\t')
55 if (strcmp(command, "next") == 0 36 target++;
56 || strcmp(command, "prev") == 0 37
57 || strcmp(command, "next_on_output") == 0 38 // Make sure that the command references an actual workspace
58 || strcmp(command, "prev_on_output") == 0 39 // not a command about workspaces
59 || strcmp(command, "number") == 0 40 if (strcmp(target, "next") == 0 ||
60 || strcmp(command, "back_and_forth") == 0 41 strcmp(target, "prev") == 0 ||
61 || strcmp(command, "current") == 0 42 strcmp(target, "next_on_output") == 0 ||
62 // Or if it already exists 43 strcmp(target, "prev_on_output") == 0 ||
63 || workspace_by_name_only(command)) { 44 strcmp(target, "number") == 0 ||
45 strcmp(target, "back_and_forth") == 0 ||
46 strcmp(target, "current") == 0)
47 {
48 free_flat_list(args);
64 continue; 49 continue;
65 } else {
66 // otherwise we found it
67 return command;
68 } 50 }
51
52 // Make sure that the workspace doesn't already exist
53 if (workspace_by_name(target)) {
54 free_flat_list(args);
55 continue;
56 }
57
58 free_flat_list(args);
59
60 sway_log(L_DEBUG, "Workspace: Found free name %s", target);
61 return target;
69 } 62 }
63 free_flat_list(args);
70 } 64 }
71 // As a fall back, get the current number of active workspaces 65 // As a fall back, get the current number of active workspaces
72 // and return that + 1 for the next workspace's name 66 // and return that + 1 for the next workspace's name
@@ -81,40 +75,55 @@ const char *workspace_next_name(void) {
81 return name; 75 return name;
82} 76}
83 77
84swayc_t *workspace_by_name_only(const char *name) { 78swayc_t *workspace_create(const char* name) {
85 int i, len = root_container.children->length; 79 swayc_t *parent;
86 for (i = 0; i < len; ++i) { 80 // Search for workspace<->output pair
87 swayc_t *op = root_container.children->items[i]; 81 int i, e = config->workspace_outputs->length;
88 int i, len = op->children->length; 82 for (i = 0; i < e; ++i) {
89 for (i = 0; i < len; ++i) { 83 struct workspace_output *wso = config->workspace_outputs->items[i];
90 swayc_t *ws = op->children->items[i]; 84 if (strcasecmp(wso->workspace, name) == 0)
91 if (strcasecmp(ws->name, name) == 0) { 85 {
92 return ws; 86 // Find output to use if it exists
87 e = root_container.children->length;
88 for (i = 0; i < e; ++i) {
89 parent = root_container.children->items[i];
90 if (strcmp(parent->name, wso->output) == 0) {
91 return new_workspace(parent, name);
92 }
93 } 93 }
94 break;
94 } 95 }
95 } 96 }
96 return NULL; 97 // Otherwise create a new one
98 parent = get_focused_container(&root_container);
99 parent = swayc_parent_by_type(parent, C_OUTPUT);
100 return new_workspace(parent, name);
101}
102
103static bool _workspace_by_name(swayc_t *view, void *data) {
104 return (view->type == C_WORKSPACE) &&
105 (strcasecmp(view->name, (char *) data) == 0);
97} 106}
98 107
99swayc_t *workspace_by_name(const char* name) { 108swayc_t *workspace_by_name(const char* name) {
100 if (strcmp(name, "prev") == 0) { 109 if (strcmp(name, "prev") == 0) {
101 return workspace_prev(); 110 return workspace_prev();
102 } else if (!strcmp(name, "prev_on_output")) { 111 }
112 else if (strcmp(name, "prev_on_output") == 0) {
103 return workspace_output_prev(); 113 return workspace_output_prev();
104 } else if (!strcmp(name, "next")) { 114 }
115 else if (strcmp(name, "next") == 0) {
105 return workspace_next(); 116 return workspace_next();
106 } else if (!strcmp(name, "next_on_output")) { 117 }
118 else if (strcmp(name, "next_on_output") == 0) {
107 return workspace_output_next(); 119 return workspace_output_next();
108 } else if (!strcmp(name, "current")) { 120 }
121 else if (strcmp(name, "current") == 0) {
109 return swayc_active_workspace(); 122 return swayc_active_workspace();
110 } else if (!strcmp(name, "back_and_forth")) {
111 if (prev_workspace_name) {
112 name = prev_workspace_name;
113 } else { // If there is no prev workspace name. just return current
114 return swayc_active_workspace();
115 }
116 } 123 }
117 return workspace_by_name_only(name); 124 else {
125 return swayc_by_test(&root_container, _workspace_by_name, (void *) name);
126 }
118} 127}
119 128
120/** 129/**
@@ -172,19 +181,19 @@ swayc_t *workspace_prev_next_impl(swayc_t *workspace, bool next) {
172 return NULL; 181 return NULL;
173} 182}
174 183
175swayc_t *workspace_output_next(void) { 184swayc_t *workspace_output_next() {
176 return workspace_output_prev_next_impl(swayc_active_output(), true); 185 return workspace_output_prev_next_impl(swayc_active_output(), true);
177} 186}
178 187
179swayc_t *workspace_next(void) { 188swayc_t *workspace_next() {
180 return workspace_prev_next_impl(swayc_active_workspace(), true); 189 return workspace_prev_next_impl(swayc_active_workspace(), true);
181} 190}
182 191
183swayc_t *workspace_output_prev(void) { 192swayc_t *workspace_output_prev() {
184 return workspace_output_prev_next_impl(swayc_active_output(), false); 193 return workspace_output_prev_next_impl(swayc_active_output(), false);
185} 194}
186 195
187swayc_t *workspace_prev(void) { 196swayc_t *workspace_prev() {
188 return workspace_prev_next_impl(swayc_active_workspace(), false); 197 return workspace_prev_next_impl(swayc_active_workspace(), false);
189} 198}
190 199
@@ -193,17 +202,17 @@ void workspace_switch(swayc_t *workspace) {
193 return; 202 return;
194 } 203 }
195 swayc_t *active_ws = swayc_active_workspace(); 204 swayc_t *active_ws = swayc_active_workspace();
196 // set workspace to prev_workspace 205 if (config->auto_back_and_forth && active_ws == workspace && prev_workspace_name) {
197 if (config->auto_back_and_forth && active_ws == workspace) { 206 swayc_t *new_ws = workspace_by_name(prev_workspace_name);
198 workspace = new_workspace(NULL, "back_and_forth"); 207 workspace = new_ws ? new_ws : workspace_create(prev_workspace_name);
199 } 208 }
200 209
201 // set prev workspace name
202 if (!prev_workspace_name 210 if (!prev_workspace_name
203 || (strcmp(prev_workspace_name, active_ws->name) 211 || (strcmp(prev_workspace_name, active_ws->name)
204 && active_ws != workspace)) { 212 && active_ws != workspace)) {
205 free(prev_workspace_name); 213 free(prev_workspace_name);
206 prev_workspace_name = strdup(active_ws->name); 214 prev_workspace_name = malloc(strlen(active_ws->name)+1);
215 strcpy(prev_workspace_name, active_ws->name);
207 } 216 }
208 217
209 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); 218 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);