summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar taiyu <taiyu.len@gmail.com>2015-09-12 02:38:03 -0700
committerLibravatar taiyu <taiyu.len@gmail.com>2015-09-12 02:38:03 -0700
commite1d18e42a8f3a597b9bf5f1bb2ab6c346e4e7983 (patch)
tree8a8ac30c539f4a63bb249b8c5e27e724a4241c9f
parentMerge pull request #177 from taiyu-len/master (diff)
downloadsway-e1d18e42a8f3a597b9bf5f1bb2ab6c346e4e7983.tar.gz
sway-e1d18e42a8f3a597b9bf5f1bb2ab6c346e4e7983.tar.zst
sway-e1d18e42a8f3a597b9bf5f1bb2ab6c346e4e7983.zip
new_workspace null behavior + testmap functions + regex
-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, 581 insertions, 370 deletions
diff --git a/include/commands.h b/include/commands.h
index 5c87be51..69ab1380 100644
--- a/include/commands.h
+++ b/include/commands.h
@@ -3,19 +3,21 @@
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
6struct cmd_handler { 12struct cmd_handler {
7 char *command; 13 const char*command;
8 enum cmd_status { 14 sway_cmd *handle;
9 CMD_SUCCESS,
10 CMD_FAILURE,
11 CMD_DEFER,
12 } (*handle)(int argc, char **argv);
13}; 15};
14 16
15enum cmd_status handle_command(char *command); 17enum cmd_status handle_command(char *command);
16// Handles commands during config 18// Handles commands during config
17enum cmd_status config_command(char *command); 19enum cmd_status config_command(char *command);
18 20
19void remove_view_from_scratchpad(); 21void remove_view_from_scratchpad(swayc_t *view);
20 22
21#endif 23#endif
diff --git a/include/config.h b/include/config.h
index 676218c8..04db3e5c 100644
--- a/include/config.h
+++ b/include/config.h
@@ -63,6 +63,10 @@ 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
66extern struct sway_config *config; 70extern struct sway_config *config;
67 71
68#endif 72#endif
diff --git a/include/container.h b/include/container.h
index a9b95229..d8590149 100644
--- a/include/container.h
+++ b/include/container.h
@@ -2,29 +2,25 @@
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
6#include "layout.h" 5#include "layout.h"
7 6
8enum swayc_types{ 7enum swayc_types {
9 C_ROOT, 8 C_ROOT = 1 << 0,
10 C_OUTPUT, 9 C_OUTPUT = 1 << 1,
11 C_WORKSPACE, 10 C_WORKSPACE = 1 << 2,
12 C_CONTAINER, 11 C_CONTAINER = 1 << 3,
13 C_VIEW, 12 C_VIEW = 1 << 4,
14 // Keep last 13 C_TYPES = 5,
15 C_TYPES,
16}; 14};
17 15
18 16enum swayc_layouts {
19enum swayc_layouts{ 17 L_NONE = 1 << 0,
20 L_NONE, 18 L_HORIZ = 1 << 1,
21 L_HORIZ, 19 L_VERT = 1 << 2,
22 L_VERT, 20 L_STACKED = 1 << 3,
23 L_STACKED, 21 L_TABBED = 1 << 4,
24 L_TABBED, 22 L_FLOATING = 1 << 5,
25 L_FLOATING, 23 L_LAYOUTS = 6,
26 // Keep last
27 L_LAYOUTS,
28}; 24};
29 25
30struct sway_container { 26struct sway_container {
@@ -35,13 +31,16 @@ struct sway_container {
35 31
36 // Not including borders or margins 32 // Not including borders or margins
37 double width, height; 33 double width, height;
34 double x, y;
38 35
39 // Used for setting floating geometry 36 // Used for setting floating geometry
40 int desired_width, desired_height; 37 int desired_width, desired_height;
41 38
42 double x, y; 39 enum visibility_mask {
40 INVISIBLE = 0,
41 VISIBLE = 1,
42 } visible;
43 43
44 bool visible;
45 bool is_floating; 44 bool is_floating;
46 bool is_focused; 45 bool is_focused;
47 46
@@ -56,70 +55,120 @@ struct sway_container {
56 struct sway_container *focused; 55 struct sway_container *focused;
57}; 56};
58 57
59enum visibility_mask { 58// swayc Creation
60 VISIBLE = 1
61};
62
63// Container Creation
64 59
60/* Creates and returns new, or an already created output.
61 * If it creates a new output, it also creates a workspace using
62 * `new_workspace(outputname, NULL);` */
65swayc_t *new_output(wlc_handle handle); 63swayc_t *new_output(wlc_handle handle);
64
65/* Creates workspace with given name, under given output.
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. */
66swayc_t *new_workspace(swayc_t *output, const char *name); 69swayc_t *new_workspace(swayc_t *output, const char *name);
70
67// Creates container Around child (parent child) -> (parent (container child)) 71// Creates container Around child (parent child) -> (parent (container child))
68swayc_t *new_container(swayc_t *child, enum swayc_layouts layout); 72swayc_t *new_container(swayc_t *child, enum swayc_layouts layout);
73
69// Creates view as a sibling of current focused container, or as child of a workspace 74// Creates view as a sibling of current focused container, or as child of a workspace
70swayc_t *new_view(swayc_t *sibling, wlc_handle handle); 75swayc_t *new_view(swayc_t *sibling, wlc_handle handle);
76
71// Creates view as a new floating view which is in the active workspace 77// Creates view as a new floating view which is in the active workspace
72swayc_t *new_floating_view(wlc_handle handle); 78swayc_t *new_floating_view(wlc_handle handle);
73 79
74// Container Destroying 80// Container Destroying
75 81// Destroys output and moves workspaces to another output
76swayc_t *destroy_output(swayc_t *output); 82swayc_t *destroy_output(swayc_t *output);
83
77// Destroys workspace if empty and returns parent pointer, else returns NULL 84// Destroys workspace if empty and returns parent pointer, else returns NULL
78swayc_t *destroy_workspace(swayc_t *workspace); 85swayc_t *destroy_workspace(swayc_t *workspace);
86
79// Destroyes container and all parent container if they are empty, returns 87// Destroyes container and all parent container if they are empty, returns
80// topmost non-empty parent. returns NULL otherwise 88// topmost non-empty parent. returns NULL otherwise
81swayc_t *destroy_container(swayc_t *container); 89swayc_t *destroy_container(swayc_t *container);
90
82// Destroys view and all empty parent containers. return topmost non-empty 91// Destroys view and all empty parent containers. return topmost non-empty
83// parent 92// parent
84swayc_t *destroy_view(swayc_t *view); 93swayc_t *destroy_view(swayc_t *view);
85 94
86// Container Lookup 95// Container Mapping and testing functions
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;
87 148
88swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data);
89swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types); 149swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types);
90swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts); 150swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts);
91// Follow focused until type/layout 151// Follow focused until type/layout
92swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types); 152swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types);
93swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts); 153swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts);
94 154
95
96swayc_t *swayc_by_handle(wlc_handle handle);
97swayc_t *swayc_by_name(const char *name);
98swayc_t *swayc_active_output(void); 155swayc_t *swayc_active_output(void);
99swayc_t *swayc_active_workspace(void); 156swayc_t *swayc_active_workspace(void);
100swayc_t *swayc_active_workspace_for(swayc_t *view); 157swayc_t *swayc_active_workspace_for(swayc_t *view);
101 158
102// Container information 159// Container information
103 160// if `parent` is the parent of `child`
104bool swayc_is_fullscreen(swayc_t *view);
105bool swayc_is_active(swayc_t *view);
106// Is `parent` the parent of `child`
107bool swayc_is_parent_of(swayc_t *parent, swayc_t *child); 161bool swayc_is_parent_of(swayc_t *parent, swayc_t *child);
108// Is `child` a child of `parent` 162// If `child` is a child of `parent`
109bool swayc_is_child_of(swayc_t *child, swayc_t *parent); 163bool swayc_is_child_of(swayc_t *child, swayc_t *parent);
110// Return gap of specified container 164// Return gap of specified container
111int swayc_gap(swayc_t *container); 165int swayc_gap(swayc_t *container);
112 166
113// Mapping functions 167bool swayc_is_fullscreen(swayc_t *view);
114 168bool swayc_is_active(swayc_t *view);
115void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
116 169
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);
122 170
171// Specialized mapping functions
123void update_visibility(swayc_t *container); 172void update_visibility(swayc_t *container);
124 173
125#endif 174#endif
diff --git a/include/stringop.h b/include/stringop.h
index dde50f13..6e80e729 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(char **argv, int argc); 22char *join_args(int argc, char **argv);
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 7343b055..3a63ea38 100644
--- a/include/workspace.h
+++ b/include/workspace.h
@@ -7,13 +7,17 @@
7 7
8extern char *prev_workspace_name; 8extern char *prev_workspace_name;
9 9
10char *workspace_next_name(void); 10// Search for available workspace name on output from config
11swayc_t *workspace_create(const char*); 11const char *workspace_output_open_name(swayc_t *output);
12// Search for any available workspace name
13const char *workspace_next_name(void);
14
15
12swayc_t *workspace_by_name(const char*); 16swayc_t *workspace_by_name(const char*);
13void workspace_switch(swayc_t*); 17void workspace_switch(swayc_t*);
14swayc_t *workspace_output_next(); 18swayc_t *workspace_output_next(void);
15swayc_t *workspace_next(); 19swayc_t *workspace_next(void);
16swayc_t *workspace_output_prev(); 20swayc_t *workspace_output_prev(void);
17swayc_t *workspace_prev(); 21swayc_t *workspace_prev(void);
18 22
19#endif 23#endif
diff --git a/sway/commands.c b/sway/commands.c
index e79746ae..74e13d6c 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -21,6 +21,35 @@
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
24static struct modifier_key { 53static struct modifier_key {
25 char *name; 54 char *name;
26 uint32_t mod; 55 uint32_t mod;
@@ -94,7 +123,7 @@ static int bindsym_sort(const void *_lbind, const void *_rbind) {
94 return (rbind->keys->length + rmod) - (lbind->keys->length + lmod); 123 return (rbind->keys->length + rmod) - (lbind->keys->length + lmod);
95} 124}
96 125
97static enum cmd_status cmd_bindsym(int argc, char **argv) { 126enum cmd_status cmd_bindsym(char *criteria, int argc, char **argv) {
98 if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1) 127 if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)
99 || !config->reading) { 128 || !config->reading) {
100 return CMD_FAILURE; 129 return CMD_FAILURE;
@@ -103,7 +132,7 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) {
103 struct sway_binding *binding = malloc(sizeof(struct sway_binding)); 132 struct sway_binding *binding = malloc(sizeof(struct sway_binding));
104 binding->keys = create_list(); 133 binding->keys = create_list();
105 binding->modifiers = 0; 134 binding->modifiers = 0;
106 binding->command = join_args(argv + 1, argc - 1); 135 binding->command = join_args(argc - 1, argv + 1);
107 136
108 list_t *split = split_string(argv[0], "+"); 137 list_t *split = split_string(argv[0], "+");
109 int i; 138 int i;
@@ -144,7 +173,7 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) {
144 return CMD_SUCCESS; 173 return CMD_SUCCESS;
145} 174}
146 175
147static enum cmd_status cmd_exec_always(int argc, char **argv) { 176enum cmd_status cmd_exec_always(char *criteria, int argc, char **argv) {
148 if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { 177 if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) {
149 return CMD_FAILURE; 178 return CMD_FAILURE;
150 } 179 }
@@ -160,7 +189,7 @@ static enum cmd_status cmd_exec_always(int argc, char **argv) {
160 } 189 }
161 /* Child process */ 190 /* Child process */
162 if (pid == 0) { 191 if (pid == 0) {
163 char *args = join_args(argv, argc); 192 char *args = join_args(argc, argv);
164 sway_log(L_DEBUG, "Executing %s", args); 193 sway_log(L_DEBUG, "Executing %s", args);
165 execl("/bin/sh", "sh", "-c", args, (char *)NULL); 194 execl("/bin/sh", "sh", "-c", args, (char *)NULL);
166 /* Execl doesnt return unless failure */ 195 /* Execl doesnt return unless failure */
@@ -172,17 +201,17 @@ static enum cmd_status cmd_exec_always(int argc, char **argv) {
172 return CMD_SUCCESS; 201 return CMD_SUCCESS;
173} 202}
174 203
175static enum cmd_status cmd_exec(int argc, char **argv) { 204enum cmd_status cmd_exec(char *criteria, int argc, char **argv) {
176 if (!config->active) { 205 if (!config->active) {
177 return CMD_DEFER; 206 return CMD_DEFER;
178 } 207 }
179 if (config->reloading) { 208 if (config->reloading) {
180 char *args = join_args(argv, argc); 209 char *args = join_args(argc, argv);
181 sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); 210 sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
182 free(args); 211 free(args);
183 return CMD_SUCCESS; 212 return CMD_SUCCESS;
184 } 213 }
185 return cmd_exec_always(argc, argv); 214 return cmd_exec_always(criteria, argc, argv);
186} 215}
187 216
188static void kill_views(swayc_t *container, void *data) { 217static void kill_views(swayc_t *container, void *data) {
@@ -191,18 +220,19 @@ static void kill_views(swayc_t *container, void *data) {
191 } 220 }
192} 221}
193 222
194static enum cmd_status cmd_exit(int argc, char **argv) { 223enum cmd_status cmd_exit(char *criteria, int argc, char **argv) {
224 (void) argv;
195 if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0) 225 if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)
196 || config->reading || !config->active) { 226 || config->reading || !config->active) {
197 return CMD_FAILURE; 227 return CMD_FAILURE;
198 } 228 }
199 // Close all views 229 // Close all views
200 container_map(&root_container, kill_views, NULL); 230 swayc_map(kill_views, NULL);
201 sway_terminate(); 231 sway_terminate();
202 return CMD_SUCCESS; 232 return CMD_SUCCESS;
203} 233}
204 234
205static enum cmd_status cmd_floating(int argc, char **argv) { 235enum cmd_status cmd_floating(char *criteria, int argc, char **argv) {
206 if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1) 236 if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)
207 || config->reading || !config->active) { 237 || config->reading || !config->active) {
208 return CMD_FAILURE; 238 return CMD_FAILURE;
@@ -264,7 +294,7 @@ static enum cmd_status cmd_floating(int argc, char **argv) {
264 return CMD_SUCCESS; 294 return CMD_SUCCESS;
265} 295}
266 296
267static enum cmd_status cmd_floating_mod(int argc, char **argv) { 297enum cmd_status cmd_floating_mod(char *criteria, int argc, char **argv) {
268 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1) 298 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)
269 || !config->reading) { 299 || !config->reading) {
270 return CMD_FAILURE; 300 return CMD_FAILURE;
@@ -289,7 +319,7 @@ static enum cmd_status cmd_floating_mod(int argc, char **argv) {
289 return CMD_SUCCESS; 319 return CMD_SUCCESS;
290} 320}
291 321
292static enum cmd_status cmd_focus(int argc, char **argv) { 322enum cmd_status cmd_focus(char *criteria, int argc, char **argv) {
293 static int floating_toggled_index = 0; 323 static int floating_toggled_index = 0;
294 static int tiled_toggled_index = 0; 324 static int tiled_toggled_index = 0;
295 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1) 325 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)
@@ -347,7 +377,7 @@ static enum cmd_status cmd_focus(int argc, char **argv) {
347 return CMD_SUCCESS; 377 return CMD_SUCCESS;
348} 378}
349 379
350static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) { 380enum cmd_status cmd_focus_follows_mouse(char *criteria, int argc, char **argv) {
351 if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) { 381 if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) {
352 return CMD_FAILURE; 382 return CMD_FAILURE;
353 } 383 }
@@ -356,6 +386,21 @@ static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
356 return CMD_SUCCESS; 386 return CMD_SUCCESS;
357} 387}
358 388
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, 2)) {
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
359static void hide_view_in_scratchpad(swayc_t *sp_view) { 404static void hide_view_in_scratchpad(swayc_t *sp_view) {
360 if(sp_view == NULL) { 405 if(sp_view == NULL) {
361 return; 406 return;
@@ -372,7 +417,7 @@ static void hide_view_in_scratchpad(swayc_t *sp_view) {
372 set_focused_container(container_under_pointer()); 417 set_focused_container(container_under_pointer());
373} 418}
374 419
375static enum cmd_status cmd_mode(int argc, char **argv) { 420enum cmd_status cmd_mode(char *criteria, int argc, char **argv) {
376 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { 421 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
377 return CMD_FAILURE; 422 return CMD_FAILURE;
378 } 423 }
@@ -381,7 +426,7 @@ static enum cmd_status cmd_mode(int argc, char **argv) {
381 return CMD_FAILURE; 426 return CMD_FAILURE;
382 } 427 }
383 428
384 char *mode_name = join_args(argv, argc - mode_make); 429 char *mode_name = join_args(argc - mode_make, argv);
385 struct sway_mode *mode = NULL; 430 struct sway_mode *mode = NULL;
386 // Find mode 431 // Find mode
387 int i, len = config->modes->length; 432 int i, len = config->modes->length;
@@ -411,7 +456,7 @@ static enum cmd_status cmd_mode(int argc, char **argv) {
411 return CMD_SUCCESS; 456 return CMD_SUCCESS;
412} 457}
413 458
414static enum cmd_status cmd_move(int argc, char **argv) { 459enum cmd_status cmd_move(char *criteria, int argc, char **argv) {
415 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1) 460 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)
416 || config->reading || !config->active) { 461 || config->reading || !config->active) {
417 return CMD_FAILURE; 462 return CMD_FAILURE;
@@ -444,11 +489,7 @@ static enum cmd_status cmd_move(int argc, char **argv) {
444 // move "container to workspace number x" 489 // move "container to workspace number x"
445 ws_name = argv[4]; 490 ws_name = argv[4];
446 } 491 }
447 492 swayc_t *ws = new_workspace(NULL, ws_name);
448 swayc_t *ws = workspace_by_name(ws_name);
449 if (ws == NULL) {
450 ws = workspace_create(ws_name);
451 }
452 move_container_to(view, get_focused_container(ws)); 493 move_container_to(view, get_focused_container(ws));
453 } else if (strcasecmp(argv[0], "scratchpad") == 0) { 494 } else if (strcasecmp(argv[0], "scratchpad") == 0) {
454 if (view->type != C_CONTAINER && view->type != C_VIEW) { 495 if (view->type != C_CONTAINER && view->type != C_VIEW) {
@@ -482,7 +523,7 @@ static enum cmd_status cmd_move(int argc, char **argv) {
482 return CMD_SUCCESS; 523 return CMD_SUCCESS;
483} 524}
484 525
485static enum cmd_status cmd_orientation(int argc, char **argv) { 526enum cmd_status cmd_orientation(char *criteria, int argc, char **argv) {
486 if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1) 527 if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)
487 || !config->reading) { 528 || !config->reading) {
488 return CMD_FAILURE; 529 return CMD_FAILURE;
@@ -499,7 +540,7 @@ static enum cmd_status cmd_orientation(int argc, char **argv) {
499 return CMD_SUCCESS; 540 return CMD_SUCCESS;
500} 541}
501 542
502static enum cmd_status cmd_output(int argc, char **argv) { 543enum cmd_status cmd_output(char *criteria, int argc, char **argv) {
503 if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { 544 if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
504 return CMD_FAILURE; 545 return CMD_FAILURE;
505 } 546 }
@@ -564,7 +605,7 @@ static enum cmd_status cmd_output(int argc, char **argv) {
564 return CMD_SUCCESS; 605 return CMD_SUCCESS;
565} 606}
566 607
567static enum cmd_status cmd_gaps(int argc, char **argv) { 608enum cmd_status cmd_gaps(char *criteria, int argc, char **argv) {
568 if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) { 609 if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
569 return CMD_FAILURE; 610 return CMD_FAILURE;
570 } 611 }
@@ -698,15 +739,14 @@ static enum cmd_status cmd_gaps(int argc, char **argv) {
698 top = &root_container; 739 top = &root_container;
699 } 740 }
700 int top_gap = top->gaps; 741 int top_gap = top->gaps;
701 container_map(top, method == SET ? set_gaps : add_gaps, &amount); 742 swayc_map_r(top, method == SET ? set_gaps : add_gaps, &amount);
702 top->gaps = top_gap; 743 top->gaps = top_gap;
703 arrange_windows(top, -1, -1); 744 arrange_windows(top, -1, -1);
704 } 745 }
705
706 return CMD_SUCCESS; 746 return CMD_SUCCESS;
707} 747}
708 748
709static enum cmd_status cmd_kill(int argc, char **argv) { 749enum cmd_status cmd_kill(char *criteria, int argc, char **argv) {
710 if (config->reading || !config->active) { 750 if (config->reading || !config->active) {
711 return CMD_FAILURE; 751 return CMD_FAILURE;
712 } 752 }
@@ -715,7 +755,7 @@ static enum cmd_status cmd_kill(int argc, char **argv) {
715 return CMD_SUCCESS; 755 return CMD_SUCCESS;
716} 756}
717 757
718static enum cmd_status cmd_layout(int argc, char **argv) { 758enum cmd_status cmd_layout(char *criteria, int argc, char **argv) {
719 if (!checkarg(argc, "layout", EXPECTED_MORE_THAN, 0) 759 if (!checkarg(argc, "layout", EXPECTED_MORE_THAN, 0)
720 || config->reading || !config->active) { 760 || config->reading || !config->active) {
721 return CMD_FAILURE; 761 return CMD_FAILURE;
@@ -741,7 +781,7 @@ static enum cmd_status cmd_layout(int argc, char **argv) {
741 return CMD_SUCCESS; 781 return CMD_SUCCESS;
742} 782}
743 783
744static enum cmd_status cmd_reload(int argc, char **argv) { 784enum cmd_status cmd_reload(char *criteria, int argc, char **argv) {
745 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0) 785 if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)
746 || config->reading 786 || config->reading
747 || !load_config(NULL)) { 787 || !load_config(NULL)) {
@@ -751,7 +791,7 @@ static enum cmd_status cmd_reload(int argc, char **argv) {
751 return CMD_SUCCESS; 791 return CMD_SUCCESS;
752} 792}
753 793
754static enum cmd_status cmd_resize(int argc, char **argv) { 794enum cmd_status cmd_resize(char *criteria, int argc, char **argv) {
755 if (!checkarg(argc, "resize", EXPECTED_AT_LEAST, 3) 795 if (!checkarg(argc, "resize", EXPECTED_AT_LEAST, 3)
756 || config->reading || !config->active) { 796 || config->reading || !config->active) {
757 return CMD_FAILURE; 797 return CMD_FAILURE;
@@ -781,7 +821,7 @@ static enum cmd_status cmd_resize(int argc, char **argv) {
781 return CMD_SUCCESS; 821 return CMD_SUCCESS;
782} 822}
783 823
784static swayc_t *fetch_view_from_scratchpad() { 824static swayc_t *fetch_view_from_scratchpad(void) {
785 if (sp_index >= scratchpad->length) { 825 if (sp_index >= scratchpad->length) {
786 sp_index = 0; 826 sp_index = 0;
787 } 827 }
@@ -826,7 +866,7 @@ void remove_view_from_scratchpad(swayc_t *view) {
826 } 866 }
827} 867}
828 868
829static enum cmd_status cmd_scratchpad(int argc, char **argv) { 869enum cmd_status cmd_scratchpad(char *criteria, int argc, char **argv) {
830 if (!checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1) 870 if (!checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1)
831 || config->reading || !config->active) { 871 || config->reading || !config->active) {
832 return CMD_FAILURE; 872 return CMD_FAILURE;
@@ -860,7 +900,7 @@ static int compare_set(const void *_l, const void *_r) {
860 return strlen((*r)->name) - strlen((*l)->name); 900 return strlen((*r)->name) - strlen((*l)->name);
861} 901}
862 902
863static enum cmd_status cmd_set(int argc, char **argv) { 903enum cmd_status cmd_set(char *criteria, int argc, char **argv) {
864 if (!checkarg(argc, "set", EXPECTED_AT_LEAST, 2) 904 if (!checkarg(argc, "set", EXPECTED_AT_LEAST, 2)
865 || !config->reading) { 905 || !config->reading) {
866 return CMD_FAILURE; 906 return CMD_FAILURE;
@@ -883,11 +923,11 @@ static enum cmd_status cmd_set(int argc, char **argv) {
883 list_add(config->symbols, var); 923 list_add(config->symbols, var);
884 list_sort(config->symbols, compare_set); 924 list_sort(config->symbols, compare_set);
885 } 925 }
886 var->value = join_args(argv + 1, argc - 1); 926 var->value = join_args(argc - 1, argv + 1);
887 return CMD_SUCCESS; 927 return CMD_SUCCESS;
888} 928}
889 929
890static enum cmd_status _do_split(int argc, char **argv, int layout) { 930static enum cmd_status _do_split(char *criteria, int argc, char **argv, int layout) {
891 char *name = layout == L_VERT ? "splitv" : 931 char *name = layout == L_VERT ? "splitv" :
892 layout == L_HORIZ ? "splith" : "split"; 932 layout == L_HORIZ ? "splith" : "split";
893 if (!checkarg(argc, name, EXPECTED_EQUAL_TO, 0) 933 if (!checkarg(argc, name, EXPECTED_EQUAL_TO, 0)
@@ -919,16 +959,16 @@ static enum cmd_status _do_split(int argc, char **argv, int layout) {
919 return CMD_SUCCESS; 959 return CMD_SUCCESS;
920} 960}
921 961
922static enum cmd_status cmd_split(int argc, char **argv) { 962enum cmd_status cmd_split(char *criteria, int argc, char **argv) {
923 if (!checkarg(argc, "split", EXPECTED_EQUAL_TO, 1) 963 if (!checkarg(argc, "split", EXPECTED_EQUAL_TO, 1)
924 || config->reading || !config->active) { 964 || config->reading || !config->active) {
925 return CMD_FAILURE; 965 return CMD_FAILURE;
926 } 966 }
927 967
928 if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { 968 if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) {
929 _do_split(argc - 1, argv + 1, L_VERT); 969 _do_split(criteria, argc - 1, argv + 1, L_VERT);
930 } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) { 970 } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) {
931 _do_split(argc - 1, argv + 1, L_HORIZ); 971 _do_split(criteria, argc - 1, argv + 1, L_HORIZ);
932 } else { 972 } else {
933 sway_log(L_ERROR, "Invalid split command (expected either horiziontal or vertical)."); 973 sway_log(L_ERROR, "Invalid split command (expected either horiziontal or vertical).");
934 return CMD_FAILURE; 974 return CMD_FAILURE;
@@ -936,15 +976,15 @@ static enum cmd_status cmd_split(int argc, char **argv) {
936 return CMD_SUCCESS; 976 return CMD_SUCCESS;
937} 977}
938 978
939static enum cmd_status cmd_splitv(int argc, char **argv) { 979enum cmd_status cmd_splitv(char *criteria, int argc, char **argv) {
940 return _do_split(argc, argv, L_VERT); 980 return _do_split(criteria, argc, argv, L_VERT);
941} 981}
942 982
943static enum cmd_status cmd_splith(int argc, char **argv) { 983enum cmd_status cmd_splith(char *criteria, int argc, char **argv) {
944 return _do_split(argc, argv, L_HORIZ); 984 return _do_split(criteria, argc, argv, L_HORIZ);
945} 985}
946 986
947static enum cmd_status cmd_log_colors(int argc, char **argv) { 987enum cmd_status cmd_log_colors(char *criteria, int argc, char **argv) {
948 if (!checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1) 988 if (!checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1)
949 || !config->reading) { 989 || !config->reading) {
950 return CMD_FAILURE; 990 return CMD_FAILURE;
@@ -960,7 +1000,7 @@ static enum cmd_status cmd_log_colors(int argc, char **argv) {
960 return CMD_SUCCESS; 1000 return CMD_SUCCESS;
961} 1001}
962 1002
963static enum cmd_status cmd_fullscreen(int argc, char **argv) { 1003enum cmd_status cmd_fullscreen(char *criteria, int argc, char **argv) {
964 if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0) 1004 if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0)
965 || config->reading || !config->active) { 1005 || config->reading || !config->active) {
966 return CMD_FAILURE; 1006 return CMD_FAILURE;
@@ -980,7 +1020,7 @@ static enum cmd_status cmd_fullscreen(int argc, char **argv) {
980 return CMD_SUCCESS; 1020 return CMD_SUCCESS;
981} 1021}
982 1022
983static enum cmd_status cmd_workspace(int argc, char **argv) { 1023enum cmd_status cmd_workspace(char *criteria, int argc, char **argv) {
984 if (!checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1)) { 1024 if (!checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1)) {
985 return CMD_FAILURE; 1025 return CMD_FAILURE;
986 } 1026 }
@@ -989,28 +1029,7 @@ static enum cmd_status cmd_workspace(int argc, char **argv) {
989 if (config->reading || !config->active) { 1029 if (config->reading || !config->active) {
990 return CMD_DEFER; 1030 return CMD_DEFER;
991 } 1031 }
992 // Handle workspace next/prev 1032 workspace_switch(new_workspace(NULL, argv[0]));
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);
1014 } else { 1033 } else {
1015 if (strcasecmp(argv[1], "output") == 0) { 1034 if (strcasecmp(argv[1], "output") == 0) {
1016 if (!checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 3)) { 1035 if (!checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 3)) {
@@ -1021,15 +1040,12 @@ static enum cmd_status cmd_workspace(int argc, char **argv) {
1021 wso->workspace = strdup(argv[0]); 1040 wso->workspace = strdup(argv[0]);
1022 wso->output = strdup(argv[2]); 1041 wso->output = strdup(argv[2]);
1023 list_add(config->workspace_outputs, wso); 1042 list_add(config->workspace_outputs, wso);
1024 if (!config->reading) {
1025 // TODO: Move workspace to output. (dont do so when reloading)
1026 }
1027 } 1043 }
1028 } 1044 }
1029 return CMD_SUCCESS; 1045 return CMD_SUCCESS;
1030} 1046}
1031 1047
1032static enum cmd_status cmd_ws_auto_back_and_forth(int argc, char **argv) { 1048enum cmd_status cmd_ws_auto_back_and_forth(char *criteria, int argc, char **argv) {
1033 if (!checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1)) { 1049 if (!checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1)) {
1034 return CMD_FAILURE; 1050 return CMD_FAILURE;
1035 } 1051 }
@@ -1044,7 +1060,7 @@ static enum cmd_status cmd_ws_auto_back_and_forth(int argc, char **argv) {
1044} 1060}
1045 1061
1046/* Keep alphabetized */ 1062/* Keep alphabetized */
1047static struct cmd_handler handlers[] = { 1063static const struct cmd_handler handlers[] = {
1048 { "bindsym", cmd_bindsym }, 1064 { "bindsym", cmd_bindsym },
1049 { "default_orientation", cmd_orientation }, 1065 { "default_orientation", cmd_orientation },
1050 { "exec", cmd_exec }, 1066 { "exec", cmd_exec },
@@ -1054,6 +1070,7 @@ static struct cmd_handler handlers[] = {
1054 { "floating_modifier", cmd_floating_mod }, 1070 { "floating_modifier", cmd_floating_mod },
1055 { "focus", cmd_focus }, 1071 { "focus", cmd_focus },
1056 { "focus_follows_mouse", cmd_focus_follows_mouse }, 1072 { "focus_follows_mouse", cmd_focus_follows_mouse },
1073 { "for_window", cmd_for_window },
1057 { "fullscreen", cmd_fullscreen }, 1074 { "fullscreen", cmd_fullscreen },
1058 { "gaps", cmd_gaps }, 1075 { "gaps", cmd_gaps },
1059 { "kill", cmd_kill }, 1076 { "kill", cmd_kill },
@@ -1090,6 +1107,7 @@ static struct cmd_handler *find_handler(char *line) {
1090enum cmd_status handle_command(char *exec) { 1107enum cmd_status handle_command(char *exec) {
1091 sway_log(L_INFO, "Handling command '%s'", exec); 1108 sway_log(L_INFO, "Handling command '%s'", exec);
1092 int argc; 1109 int argc;
1110 char *criteria = NULL;
1093 char **argv = split_args(exec, &argc); 1111 char **argv = split_args(exec, &argc);
1094 enum cmd_status status = CMD_FAILURE; 1112 enum cmd_status status = CMD_FAILURE;
1095 struct cmd_handler *handler; 1113 struct cmd_handler *handler;
@@ -1097,7 +1115,7 @@ enum cmd_status handle_command(char *exec) {
1097 return status; 1115 return status;
1098 } 1116 }
1099 if ((handler = find_handler(argv[0])) == NULL 1117 if ((handler = find_handler(argv[0])) == NULL
1100 || (status = handler->handle(argc - 1, argv + 1)) != CMD_SUCCESS) { 1118 || (status = handler->handle(criteria, argc - 1, argv + 1)) != CMD_SUCCESS) {
1101 sway_log(L_ERROR, "Command failed: %s", argv[0]); 1119 sway_log(L_ERROR, "Command failed: %s", argv[0]);
1102 } 1120 }
1103 free_argv(argc, argv); 1121 free_argv(argc, argv);
@@ -1108,6 +1126,7 @@ enum cmd_status config_command(char *exec) {
1108 sway_log(L_INFO, "handling config command '%s'", exec); 1126 sway_log(L_INFO, "handling config command '%s'", exec);
1109 int argc; 1127 int argc;
1110 char **argv = split_args(exec, &argc); 1128 char **argv = split_args(exec, &argc);
1129 char *criteria = NULL;
1111 enum cmd_status status = CMD_FAILURE; 1130 enum cmd_status status = CMD_FAILURE;
1112 struct cmd_handler *handler; 1131 struct cmd_handler *handler;
1113 if (!argc) { 1132 if (!argc) {
@@ -1127,7 +1146,7 @@ enum cmd_status config_command(char *exec) {
1127 for (; i < e; ++i) { 1146 for (; i < e; ++i) {
1128 argv[i] = do_var_replacement(argv[i]); 1147 argv[i] = do_var_replacement(argv[i]);
1129 } 1148 }
1130 status = handler->handle(argc - 1, argv + 1); 1149 status = handler->handle(criteria, argc - 1, argv + 1);
1131 if (status == CMD_FAILURE) { 1150 if (status == CMD_FAILURE) {
1132 sway_log(L_ERROR, "Config load failed for line `%s'", exec); 1151 sway_log(L_ERROR, "Config load failed for line `%s'", exec);
1133 } else if (status == CMD_DEFER) { 1152 } else if (status == CMD_DEFER) {
diff --git a/sway/config.c b/sway/config.c
index 23d6ac0d..da92030e 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -286,3 +286,28 @@ 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 ef0e6c55..baf84378 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -1,6 +1,7 @@
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>
4#include "config.h" 5#include "config.h"
5#include "container.h" 6#include "container.h"
6#include "workspace.h" 7#include "workspace.h"
@@ -53,26 +54,30 @@ static void free_swayc(swayc_t *cont) {
53// New containers 54// New containers
54 55
55swayc_t *new_output(wlc_handle handle) { 56swayc_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
58 // Find current outputs to see if this already exists 60 // Find current outputs to see if this already exists
59 { 61 if (name) {
60 int i, len = root_container.children->length; 62 len = root_container.children->length;
61 for (i = 0; i < len; ++i) { 63 for (i = 0; i < len; ++i) {
62 swayc_t *op = root_container.children->items[i]; 64 swayc_t *op = root_container.children->items[i];
63 const char *op_name = op->name; 65 if (strcmp(op->name, name) == 0) {
64 if (op_name && name && strcmp(op_name, name) == 0) { 66 sway_log(L_DEBUG, "restoring output %lu:%s", handle, op->name);
65 sway_log(L_DEBUG, "restoring output %lu:%s", handle, op_name);
66 return op; 67 return op;
67 } 68 }
68 } 69 }
70 } else {
71 sway_log(L_ERROR, "Output has no given name");
72 return NULL;
69 } 73 }
70 74
71 sway_log(L_DEBUG, "Added output %lu:%s", handle, name); 75 sway_log(L_DEBUG, "Adding output %lu:%s", handle, name);
72 76
77 // Find output config
73 struct output_config *oc = NULL; 78 struct output_config *oc = NULL;
74 int i; 79 len = config->output_configs->length;
75 for (i = 0; i < config->output_configs->length; ++i) { 80 for (i = 0; i < len; ++i) {
76 oc = config->output_configs->items[i]; 81 oc = config->output_configs->items[i];
77 if (strcasecmp(name, oc->name) == 0) { 82 if (strcasecmp(name, oc->name) == 0) {
78 sway_log(L_DEBUG, "Matched output config for %s", name); 83 sway_log(L_DEBUG, "Matched output config for %s", name);
@@ -86,77 +91,88 @@ swayc_t *new_output(wlc_handle handle) {
86 } 91 }
87 92
88 swayc_t *output = new_swayc(C_OUTPUT); 93 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 }
98 output->handle = handle; 94 output->handle = handle;
99 output->name = name ? strdup(name) : NULL; 95 output->name = name ? strdup(name) : NULL;
100
101 // Find position for it
102 if (oc && oc->x != -1 && oc->y != -1) {
103 sway_log(L_DEBUG, "Set %s position to %d, %d", name, oc->x, oc->y);
104 output->x = oc->x;
105 output->y = oc->y;
106 } else {
107 int x = 0;
108 for (i = 0; i < root_container.children->length; ++i) {
109 swayc_t *c = root_container.children->items[i];
110 if (c->type == C_OUTPUT) {
111 if (c->width + c->x > x) {
112 x = c->width + c->x;
113 }
114 }
115 }
116 output->x = x;
117 }
118 96
119 add_child(&root_container, output); 97 if (oc) {
120 98 // Set output width/height
121 // Create workspace 99 if (oc->width > 0 && oc->height > 0) {
122 char *ws_name = NULL; 100 output->width = oc->width;
123 if (name) { 101 output->height = oc->height;
124 for (i = 0; i < config->workspace_outputs->length; ++i) { 102 struct wlc_size geo = { .w = oc->width, .h = oc->height};
125 struct workspace_output *wso = config->workspace_outputs->items[i]; 103 wlc_output_set_resolution(handle, &geo);
126 if (strcasecmp(wso->output, name) == 0) { 104 } else {
127 sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); 105 struct wlc_size geo = *wlc_output_get_resolution(handle);
128 // Check if any other workspaces are using this name 106 output->width = geo.w;
129 if (workspace_by_name(wso->workspace)) { 107 output->height = geo.h;
130 sway_log(L_DEBUG, "But it's already taken"); 108 }
131 break; 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 }
132 } 124 }
133 sway_log(L_DEBUG, "So we're going to use it");
134 ws_name = strdup(wso->workspace);
135 break;
136 } 125 }
126 output->x = x;
137 } 127 }
138 } 128 }
139 if (!ws_name) { 129 // Add as child to root
140 ws_name = workspace_next_name(); 130 add_child(&root_container, output);
141 }
142 131
143 // create and initilize default workspace 132 // create and initilize default workspace
144 swayc_t *ws = new_workspace(output, ws_name); 133 swayc_t *ws = new_workspace(output, NULL);
145 ws->is_focused = true; 134 ws->is_focused = true;
146 135
147 free(ws_name);
148
149 return output; 136 return output;
150} 137}
151 138
152swayc_t *new_workspace(swayc_t *output, const char *name) { 139swayc_t *new_workspace(swayc_t *output, const char *name) {
153 if (!ASSERT_NONNULL(output)) { 140 swayc_t *ws = NULL;
154 return NULL; 141 struct workspace_output *wsop;
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 }
155 } 174 }
156 sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle);
157 swayc_t *workspace = new_swayc(C_WORKSPACE); 175 swayc_t *workspace = new_swayc(C_WORKSPACE);
158
159 // TODO: default_layout
160 if (config->default_layout != L_NONE) { 176 if (config->default_layout != L_NONE) {
161 workspace->layout = config->default_layout; 177 workspace->layout = config->default_layout;
162 } else if (config->default_orientation != L_NONE) { 178 } else if (config->default_orientation != L_NONE) {
@@ -374,7 +390,7 @@ swayc_t *destroy_view(swayc_t *view) {
374// Container lookup 390// Container lookup
375 391
376 392
377swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { 393swayc_t *swayc_by_test_r(swayc_t *container, swayc_test_func test, void *data) {
378 if (!container->children) { 394 if (!container->children) {
379 return NULL; 395 return NULL;
380 } 396 }
@@ -393,7 +409,7 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
393 if (test(child, data)) { 409 if (test(child, data)) {
394 return child; 410 return child;
395 } else { 411 } else {
396 swayc_t *res = swayc_by_test(child, test, data); 412 swayc_t *res = swayc_by_test_r(child, test, data);
397 if (res) { 413 if (res) {
398 return res; 414 return res;
399 } 415 }
@@ -401,18 +417,193 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
401 } 417 }
402 return NULL; 418 return NULL;
403} 419}
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}
404 483
405static bool test_name(swayc_t *view, void *data) { 484void add_gaps(swayc_t *view, void *_data) {
406 if (!view && !view->name) { 485 int *data = _data;
407 return false; 486 if (view->type == C_WORKSPACE || view->type == C_VIEW) {
487 if ((view->gaps += *data) < 0) {
488 view->gaps = 0;
489 }
408 } 490 }
409 return strcmp(view->name, data) == 0;
410} 491}
411 492
412swayc_t *swayc_by_name(const char *name) { 493// Test functions
413 return swayc_by_test(&root_container, test_name, (void *)name); 494bool test_name(swayc_t *view, void *data) {
495 return view->name && strcmp(view->name, data) == 0;
414} 496}
415 497
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
416swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { 607swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
417 if (!ASSERT_NONNULL(container)) { 608 if (!ASSERT_NONNULL(container)) {
418 return NULL; 609 return NULL;
@@ -465,42 +656,6 @@ swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts layout) {
465 return container; 656 return container;
466} 657}
467 658
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
504swayc_t *swayc_active_output(void) { 659swayc_t *swayc_active_output(void) {
505 return root_container.focused; 660 return root_container.focused;
506} 661}
@@ -533,11 +688,13 @@ swayc_t *swayc_active_workspace_for(swayc_t *cont) {
533// Container information 688// Container information
534 689
535bool swayc_is_fullscreen(swayc_t *view) { 690bool swayc_is_fullscreen(swayc_t *view) {
536 return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN); 691 return view && view->type == C_VIEW
692 && wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN;
537} 693}
538 694
539bool swayc_is_active(swayc_t *view) { 695bool swayc_is_active(swayc_t *view) {
540 return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED); 696 return view && view->type == C_VIEW
697 && wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED;
541} 698}
542 699
543bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) { 700bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) {
@@ -566,25 +723,6 @@ int swayc_gap(swayc_t *container) {
566 723
567// Mapping 724// Mapping
568 725
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
588void update_visibility_output(swayc_t *container, wlc_handle output) { 726void update_visibility_output(swayc_t *container, wlc_handle output) {
589 // Inherit visibility 727 // Inherit visibility
590 swayc_t *parent = container->parent; 728 swayc_t *parent = container->parent;
@@ -653,24 +791,3 @@ void update_visibility(swayc_t *container) {
653 } 791 }
654} 792}
655 793
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 096df53c..1a8138f8 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_handle(output); 129 swayc_t *c = swayc_by_test(test_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_handle(output); 137 swayc_t *c = swayc_by_test(test_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_handle(parent); 155 focused = swayc_by_test(test_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_handle(handle); 224 swayc_t *view = swayc_by_test(test_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_handle(handle); 261 swayc_t *view = swayc_by_test(test_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_handle(view); 277 swayc_t *c = swayc_by_test(test_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 abf2ed0c..86518bc6 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 container_map(&root_container, ipc_get_workspaces_callback, workspaces); 210 swayc_map(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 container_map(&root_container, ipc_get_outputs_callback, outputs); 219 swayc_map(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 191e40c8..54faf74c 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(char **argv, int argc) { 261char *join_args(int argc, char **argv) {
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 658f79bc..80141f71 100644
--- a/sway/workspace.c
+++ b/sway/workspace.c
@@ -15,7 +15,26 @@
15 15
16char *prev_workspace_name = NULL; 16char *prev_workspace_name = NULL;
17 17
18char *workspace_next_name(void) { 18static swayc_t *workspace_by_name_only(const char *name);
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) {
19 sway_log(L_DEBUG, "Workspace: Generating new name"); 38 sway_log(L_DEBUG, "Workspace: Generating new name");
20 int i; 39 int i;
21 int l = 1; 40 int l = 1;
@@ -25,42 +44,29 @@ char *workspace_next_name(void) {
25 44
26 for (i = 0; i < mode->bindings->length; ++i) { 45 for (i = 0; i < mode->bindings->length; ++i) {
27 struct sway_binding *binding = mode->bindings->items[i]; 46 struct sway_binding *binding = mode->bindings->items[i];
28 const char* command = binding->command; 47 const char *command = binding->command;
29 list_t *args = split_string(command, " "); 48 const char *ws = "workspace";
30 49 const int wslen = sizeof("workspace") - 1;
31 if (strcmp("workspace", args->items[0]) == 0 && args->length > 1) { 50 if (strncmp(ws, command, wslen) == 0) {
32 sway_log(L_DEBUG, "Got valid workspace command for target: '%s'", (char *)args->items[1]); 51 command += wslen;
33 char* target = malloc(strlen(args->items[1]) + 1); 52 // Skip whitespace
34 strcpy(target, args->items[1]); 53 command += strspn(command, whitespace);
35 while (*target == ' ' || *target == '\t') 54 // make sure its not a special command
36 target++; 55 if (strcmp(command, "next") == 0
37 56 || strcmp(command, "prev") == 0
38 // Make sure that the command references an actual workspace 57 || strcmp(command, "next_on_output") == 0
39 // not a command about workspaces 58 || strcmp(command, "prev_on_output") == 0
40 if (strcmp(target, "next") == 0 || 59 || strcmp(command, "number") == 0
41 strcmp(target, "prev") == 0 || 60 || strcmp(command, "back_and_forth") == 0
42 strcmp(target, "next_on_output") == 0 || 61 || strcmp(command, "current") == 0
43 strcmp(target, "prev_on_output") == 0 || 62 // Or if it already exists
44 strcmp(target, "number") == 0 || 63 || workspace_by_name_only(command)) {
45 strcmp(target, "back_and_forth") == 0 ||
46 strcmp(target, "current") == 0)
47 {
48 free_flat_list(args);
49 continue; 64 continue;
65 } else {
66 // otherwise we found it
67 return command;
50 } 68 }
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;
62 } 69 }
63 free_flat_list(args);
64 } 70 }
65 // As a fall back, get the current number of active workspaces 71 // As a fall back, get the current number of active workspaces
66 // and return that + 1 for the next workspace's name 72 // and return that + 1 for the next workspace's name
@@ -75,55 +81,40 @@ char *workspace_next_name(void) {
75 return name; 81 return name;
76} 82}
77 83
78swayc_t *workspace_create(const char* name) { 84swayc_t *workspace_by_name_only(const char *name) {
79 swayc_t *parent; 85 int i, len = root_container.children->length;
80 // Search for workspace<->output pair 86 for (i = 0; i < len; ++i) {
81 int i, e = config->workspace_outputs->length; 87 swayc_t *op = root_container.children->items[i];
82 for (i = 0; i < e; ++i) { 88 int i, len = op->children->length;
83 struct workspace_output *wso = config->workspace_outputs->items[i]; 89 for (i = 0; i < len; ++i) {
84 if (strcasecmp(wso->workspace, name) == 0) 90 swayc_t *ws = op->children->items[i];
85 { 91 if (strcasecmp(ws->name, name) == 0) {
86 // Find output to use if it exists 92 return ws;
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;
95 } 94 }
96 } 95 }
97 // Otherwise create a new one 96 return NULL;
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);
106} 97}
107 98
108swayc_t *workspace_by_name(const char* name) { 99swayc_t *workspace_by_name(const char* name) {
109 if (strcmp(name, "prev") == 0) { 100 if (strcmp(name, "prev") == 0) {
110 return workspace_prev(); 101 return workspace_prev();
111 } 102 } else if (!strcmp(name, "prev_on_output")) {
112 else if (strcmp(name, "prev_on_output") == 0) {
113 return workspace_output_prev(); 103 return workspace_output_prev();
114 } 104 } else if (!strcmp(name, "next")) {
115 else if (strcmp(name, "next") == 0) {
116 return workspace_next(); 105 return workspace_next();
117 } 106 } else if (!strcmp(name, "next_on_output")) {
118 else if (strcmp(name, "next_on_output") == 0) {
119 return workspace_output_next(); 107 return workspace_output_next();
120 } 108 } else if (!strcmp(name, "current")) {
121 else if (strcmp(name, "current") == 0) {
122 return swayc_active_workspace(); 109 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 }
123 } 116 }
124 else { 117 return workspace_by_name_only(name);
125 return swayc_by_test(&root_container, _workspace_by_name, (void *) name);
126 }
127} 118}
128 119
129/** 120/**
@@ -181,19 +172,19 @@ swayc_t *workspace_prev_next_impl(swayc_t *workspace, bool next) {
181 return NULL; 172 return NULL;
182} 173}
183 174
184swayc_t *workspace_output_next() { 175swayc_t *workspace_output_next(void) {
185 return workspace_output_prev_next_impl(swayc_active_output(), true); 176 return workspace_output_prev_next_impl(swayc_active_output(), true);
186} 177}
187 178
188swayc_t *workspace_next() { 179swayc_t *workspace_next(void) {
189 return workspace_prev_next_impl(swayc_active_workspace(), true); 180 return workspace_prev_next_impl(swayc_active_workspace(), true);
190} 181}
191 182
192swayc_t *workspace_output_prev() { 183swayc_t *workspace_output_prev(void) {
193 return workspace_output_prev_next_impl(swayc_active_output(), false); 184 return workspace_output_prev_next_impl(swayc_active_output(), false);
194} 185}
195 186
196swayc_t *workspace_prev() { 187swayc_t *workspace_prev(void) {
197 return workspace_prev_next_impl(swayc_active_workspace(), false); 188 return workspace_prev_next_impl(swayc_active_workspace(), false);
198} 189}
199 190
@@ -202,17 +193,17 @@ void workspace_switch(swayc_t *workspace) {
202 return; 193 return;
203 } 194 }
204 swayc_t *active_ws = swayc_active_workspace(); 195 swayc_t *active_ws = swayc_active_workspace();
205 if (config->auto_back_and_forth && active_ws == workspace && prev_workspace_name) { 196 // set workspace to prev_workspace
206 swayc_t *new_ws = workspace_by_name(prev_workspace_name); 197 if (config->auto_back_and_forth && active_ws == workspace) {
207 workspace = new_ws ? new_ws : workspace_create(prev_workspace_name); 198 workspace = new_workspace(NULL, "back_and_forth");
208 } 199 }
209 200
201 // set prev workspace name
210 if (!prev_workspace_name 202 if (!prev_workspace_name
211 || (strcmp(prev_workspace_name, active_ws->name) 203 || (strcmp(prev_workspace_name, active_ws->name)
212 && active_ws != workspace)) { 204 && active_ws != workspace)) {
213 free(prev_workspace_name); 205 free(prev_workspace_name);
214 prev_workspace_name = malloc(strlen(active_ws->name)+1); 206 prev_workspace_name = strdup(active_ws->name);
215 strcpy(prev_workspace_name, active_ws->name);
216 } 207 }
217 208
218 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); 209 sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);