diff options
-rw-r--r-- | include/sway/tree/container.h | 2 | ||||
-rw-r--r-- | include/sway/tree/view.h | 5 | ||||
-rw-r--r-- | include/sway/tree/workspace.h | 4 | ||||
-rw-r--r-- | sway/commands/layout.c | 105 | ||||
-rw-r--r-- | sway/commands/move.c | 262 | ||||
-rw-r--r-- | sway/commands/rename.c | 10 | ||||
-rw-r--r-- | sway/commands/workspace.c | 50 | ||||
-rw-r--r-- | sway/criteria.c | 26 | ||||
-rw-r--r-- | sway/sway.5.scd | 59 | ||||
-rw-r--r-- | sway/tree/layout.c | 4 | ||||
-rw-r--r-- | sway/tree/view.c | 18 | ||||
-rw-r--r-- | sway/tree/workspace.c | 11 |
12 files changed, 378 insertions, 178 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 44ff9f7d..16a180f8 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -113,7 +113,7 @@ struct sway_container { | |||
113 | 113 | ||
114 | enum sway_container_type type; | 114 | enum sway_container_type type; |
115 | enum sway_container_layout layout; | 115 | enum sway_container_layout layout; |
116 | enum sway_container_layout prev_layout; | 116 | enum sway_container_layout prev_split_layout; |
117 | 117 | ||
118 | bool is_sticky; | 118 | bool is_sticky; |
119 | 119 | ||
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index e91d2a20..c2225bcb 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -320,6 +320,11 @@ void view_update_title(struct sway_view *view, bool force); | |||
320 | void view_execute_criteria(struct sway_view *view); | 320 | void view_execute_criteria(struct sway_view *view); |
321 | 321 | ||
322 | /** | 322 | /** |
323 | * Find any view that has the given mark and return it. | ||
324 | */ | ||
325 | struct sway_view *view_find_mark(char *mark); | ||
326 | |||
327 | /** | ||
323 | * Find any view that has the given mark and remove the mark from the view. | 328 | * Find any view that has the given mark and remove the mark from the view. |
324 | * Returns true if it matched a view. | 329 | * Returns true if it matched a view. |
325 | */ | 330 | */ |
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 3337f2c8..239cbbdb 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef _SWAY_WORKSPACE_H | 1 | #ifndef _SWAY_WORKSPACE_H |
2 | #define _SWAY_WORKSPACE_H | 2 | #define _SWAY_WORKSPACE_H |
3 | 3 | ||
4 | #include <stdbool.h> | ||
4 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
5 | 6 | ||
6 | struct sway_view; | 7 | struct sway_view; |
@@ -17,7 +18,8 @@ extern char *prev_workspace_name; | |||
17 | 18 | ||
18 | char *workspace_next_name(const char *output_name); | 19 | char *workspace_next_name(const char *output_name); |
19 | 20 | ||
20 | bool workspace_switch(struct sway_container *workspace); | 21 | bool workspace_switch(struct sway_container *workspace, |
22 | bool no_auto_back_and_forth); | ||
21 | 23 | ||
22 | struct sway_container *workspace_by_number(const char* name); | 24 | struct sway_container *workspace_by_number(const char* name); |
23 | 25 | ||
diff --git a/sway/commands/layout.c b/sway/commands/layout.c index c446f1f9..f4e4dda9 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <stdbool.h> | ||
1 | #include <string.h> | 2 | #include <string.h> |
2 | #include <strings.h> | 3 | #include <strings.h> |
3 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
@@ -5,6 +6,26 @@ | |||
5 | #include "sway/tree/container.h" | 6 | #include "sway/tree/container.h" |
6 | #include "log.h" | 7 | #include "log.h" |
7 | 8 | ||
9 | static bool parse_layout_string(char *s, enum sway_container_layout *ptr) { | ||
10 | if (strcasecmp(s, "splith") == 0) { | ||
11 | *ptr = L_HORIZ; | ||
12 | } else if (strcasecmp(s, "splitv") == 0) { | ||
13 | *ptr = L_VERT; | ||
14 | } else if (strcasecmp(s, "tabbed") == 0) { | ||
15 | *ptr = L_TABBED; | ||
16 | } else if (strcasecmp(s, "stacking") == 0) { | ||
17 | *ptr = L_STACKED; | ||
18 | } else { | ||
19 | return false; | ||
20 | } | ||
21 | return true; | ||
22 | } | ||
23 | |||
24 | static const char* expected_syntax = | ||
25 | "Expected 'layout default|tabbed|stacking|splitv|splith' or " | ||
26 | "'layout toggle [split|all]' or " | ||
27 | "'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'"; | ||
28 | |||
8 | struct cmd_results *cmd_layout(int argc, char **argv) { | 29 | struct cmd_results *cmd_layout(int argc, char **argv) { |
9 | struct cmd_results *error = NULL; | 30 | struct cmd_results *error = NULL; |
10 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { | 31 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { |
@@ -21,35 +42,69 @@ struct cmd_results *cmd_layout(int argc, char **argv) { | |||
21 | parent = parent->parent; | 42 | parent = parent->parent; |
22 | } | 43 | } |
23 | 44 | ||
24 | if (strcasecmp(argv[0], "default") == 0) { | 45 | enum sway_container_layout prev = parent->layout; |
25 | parent->layout = parent->prev_layout; | 46 | bool assigned_directly = parse_layout_string(argv[0], &parent->layout); |
26 | if (parent->layout == L_NONE) { | 47 | if (!assigned_directly) { |
27 | parent->layout = container_get_default_layout(parent); | 48 | if (strcasecmp(argv[0], "default") == 0) { |
28 | } | 49 | parent->layout = parent->prev_split_layout; |
29 | } else { | 50 | } else if (strcasecmp(argv[0], "toggle") == 0) { |
30 | if (parent->layout != L_TABBED && parent->layout != L_STACKED) { | 51 | if (argc == 1) { |
31 | parent->prev_layout = parent->layout; | 52 | parent->layout = |
32 | } | 53 | parent->layout == L_STACKED ? L_TABBED : |
33 | 54 | parent->layout == L_TABBED ? parent->prev_split_layout : L_STACKED; | |
34 | if (strcasecmp(argv[0], "splith") == 0) { | 55 | } else if (argc == 2) { |
35 | parent->layout = L_HORIZ; | 56 | if (strcasecmp(argv[1], "all") == 0) { |
36 | } else if (strcasecmp(argv[0], "splitv") == 0) { | 57 | parent->layout = |
37 | parent->layout = L_VERT; | 58 | parent->layout == L_HORIZ ? L_VERT : |
38 | } else if (strcasecmp(argv[0], "tabbed") == 0) { | 59 | parent->layout == L_VERT ? L_STACKED : |
39 | parent->layout = L_TABBED; | 60 | parent->layout == L_STACKED ? L_TABBED : L_HORIZ; |
40 | } else if (strcasecmp(argv[0], "stacking") == 0) { | 61 | } else if (strcasecmp(argv[1], "split") == 0) { |
41 | parent->layout = L_STACKED; | 62 | parent->layout = |
42 | } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { | 63 | parent->layout == L_HORIZ ? L_VERT : |
43 | if (parent->layout == L_HORIZ) { | 64 | parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout; |
44 | parent->layout = L_VERT; | 65 | } else { |
66 | return cmd_results_new(CMD_INVALID, "layout", expected_syntax); | ||
67 | } | ||
45 | } else { | 68 | } else { |
46 | parent->layout = L_HORIZ; | 69 | enum sway_container_layout parsed_layout; |
70 | int curr = 1; | ||
71 | for (; curr < argc; curr++) { | ||
72 | bool valid = parse_layout_string(argv[curr], &parsed_layout); | ||
73 | if ((valid && parsed_layout == parent->layout) || | ||
74 | (strcmp(argv[curr], "split") == 0 && | ||
75 | (parent->layout == L_VERT || parent->layout == L_HORIZ))) { | ||
76 | break; | ||
77 | } | ||
78 | } | ||
79 | for (int i = curr + 1; i != curr; ++i) { | ||
80 | // cycle round to find next valid layout | ||
81 | if (i >= argc) { | ||
82 | i = 1; | ||
83 | } | ||
84 | if (parse_layout_string(argv[i], &parent->layout)) { | ||
85 | break; | ||
86 | } else if (strcmp(argv[i], "split") == 0) { | ||
87 | parent->layout = | ||
88 | parent->layout == L_HORIZ ? L_VERT : | ||
89 | parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout; | ||
90 | break; | ||
91 | } // invalid layout strings are silently ignored | ||
92 | } | ||
47 | } | 93 | } |
94 | } else { | ||
95 | return cmd_results_new(CMD_INVALID, "layout", expected_syntax); | ||
48 | } | 96 | } |
49 | } | 97 | } |
50 | 98 | if (parent->layout == L_NONE) { | |
51 | container_notify_subtree_changed(parent); | 99 | parent->layout = container_get_default_layout(parent); |
52 | arrange_windows(parent); | 100 | } |
101 | if (prev != parent->layout) { | ||
102 | if (prev != L_TABBED && prev != L_STACKED) { | ||
103 | parent->prev_split_layout = prev; | ||
104 | } | ||
105 | container_notify_subtree_changed(parent); | ||
106 | arrange_windows(parent); | ||
107 | } | ||
53 | 108 | ||
54 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 109 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
55 | } | 110 | } |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 841da4c4..af3dc538 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <stdbool.h> | ||
2 | #include <string.h> | 3 | #include <string.h> |
3 | #include <strings.h> | 4 | #include <strings.h> |
4 | #include <wlr/types/wlr_cursor.h> | 5 | #include <wlr/types/wlr_cursor.h> |
@@ -16,11 +17,11 @@ | |||
16 | #include "stringop.h" | 17 | #include "stringop.h" |
17 | #include "list.h" | 18 | #include "list.h" |
18 | 19 | ||
19 | static const char* expected_syntax = | 20 | static const char *expected_syntax = |
20 | "Expected 'move <left|right|up|down> <[px] px>' or " | 21 | "Expected 'move <left|right|up|down> <[px] px>' or " |
21 | "'move <container|window> to workspace <name>' or " | 22 | "'move [--no-auto-back-and-forth] <container|window> [to] workspace <name>' or " |
22 | "'move <container|window|workspace> to output <name|direction>' or " | 23 | "'move [--no-auto-back-and-forth] <container|window|workspace> [to] output <name|direction>' or " |
23 | "'move position mouse'"; | 24 | "'move <container|window> [to] mark <mark>'"; |
24 | 25 | ||
25 | static struct sway_container *output_in_direction(const char *direction, | 26 | static struct sway_container *output_in_direction(const char *direction, |
26 | struct wlr_output *reference, int ref_lx, int ref_ly) { | 27 | struct wlr_output *reference, int ref_lx, int ref_ly) { |
@@ -52,123 +53,168 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
52 | int argc, char **argv) { | 53 | int argc, char **argv) { |
53 | struct cmd_results *error = NULL; | 54 | struct cmd_results *error = NULL; |
54 | if ((error = checkarg(argc, "move container/window", | 55 | if ((error = checkarg(argc, "move container/window", |
55 | EXPECTED_AT_LEAST, 4))) { | 56 | EXPECTED_AT_LEAST, 3))) { |
56 | return error; | 57 | return error; |
57 | } else if (strcasecmp(argv[1], "to") == 0 | 58 | } |
58 | && strcasecmp(argv[2], "workspace") == 0) { | 59 | |
59 | // move container to workspace x | 60 | if (current->type == C_WORKSPACE) { |
60 | if (current->type == C_WORKSPACE) { | 61 | if (current->children->length == 0) { |
61 | if (current->children->length == 0) { | ||
62 | return cmd_results_new(CMD_FAILURE, "move", | ||
63 | "Can't move an empty workspace"); | ||
64 | } | ||
65 | current = container_wrap_children(current); | ||
66 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { | ||
67 | return cmd_results_new(CMD_FAILURE, "move", | 62 | return cmd_results_new(CMD_FAILURE, "move", |
68 | "Can only move containers and views."); | 63 | "Can't move an empty workspace"); |
69 | } | 64 | } |
70 | struct sway_container *ws; | 65 | current = container_wrap_children(current); |
71 | char *ws_name = NULL; | 66 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { |
72 | if (argc == 5 && strcasecmp(argv[3], "number") == 0) { | 67 | return cmd_results_new(CMD_FAILURE, "move", |
73 | // move "container to workspace number x" | 68 | "Can only move containers and views."); |
74 | ws_name = strdup(argv[4]); | 69 | } |
75 | ws = workspace_by_number(ws_name); | 70 | |
76 | } else { | 71 | bool no_auto_back_and_forth = false; |
77 | ws_name = join_args(argv + 3, argc - 3); | 72 | while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) { |
78 | ws = workspace_by_name(ws_name); | 73 | no_auto_back_and_forth = true; |
74 | if (--argc < 3) { | ||
75 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
76 | } | ||
77 | ++argv; | ||
78 | } | ||
79 | while (strcasecmp(argv[1], "--no-auto-back-and-forth") == 0) { | ||
80 | no_auto_back_and_forth = true; | ||
81 | if (--argc < 3) { | ||
82 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
79 | } | 83 | } |
84 | argv++; | ||
85 | } | ||
86 | |||
87 | while (strcasecmp(argv[1], "to") == 0) { | ||
88 | if (--argc < 3) { | ||
89 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
90 | } | ||
91 | argv++; | ||
92 | } | ||
80 | 93 | ||
81 | if (config->auto_back_and_forth && prev_workspace_name) { | 94 | struct sway_container *old_parent = current->parent; |
82 | // auto back and forth move | 95 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); |
83 | struct sway_container *curr_ws = container_parent(current, C_WORKSPACE); | 96 | struct sway_container *destination = NULL; |
84 | if (curr_ws->name && strcmp(curr_ws->name, ws_name) == 0) { | 97 | |
85 | // if target workspace is the current one | 98 | // determine destination |
86 | free(ws_name); | 99 | if (strcasecmp(argv[1], "workspace") == 0) { |
87 | ws_name = strdup(prev_workspace_name); | 100 | // move container to workspace x |
101 | struct sway_container *ws; | ||
102 | if (strcasecmp(argv[2], "next") == 0 || | ||
103 | strcasecmp(argv[2], "prev") == 0 || | ||
104 | strcasecmp(argv[2], "next_on_output") == 0 || | ||
105 | strcasecmp(argv[2], "prev_on_output") == 0 || | ||
106 | strcasecmp(argv[2], "back_and_forth") == 0 || | ||
107 | strcasecmp(argv[2], "current") == 0) { | ||
108 | ws = workspace_by_name(argv[2]); | ||
109 | } else if (strcasecmp(argv[2], "back_and_forth") == 0) { | ||
110 | if (!(ws = workspace_by_name(argv[2]))) { | ||
111 | if (prev_workspace_name) { | ||
112 | ws = workspace_create(NULL, prev_workspace_name); | ||
113 | } else { | ||
114 | return cmd_results_new(CMD_FAILURE, "move", | ||
115 | "No workspace was previously active."); | ||
116 | } | ||
117 | } | ||
118 | } else { | ||
119 | char *ws_name = NULL; | ||
120 | if (strcasecmp(argv[2], "number") == 0) { | ||
121 | // move "container to workspace number x" | ||
122 | if (argc < 4) { | ||
123 | return cmd_results_new(CMD_INVALID, "move", | ||
124 | expected_syntax); | ||
125 | } | ||
126 | ws_name = strdup(argv[3]); | ||
127 | ws = workspace_by_number(ws_name); | ||
128 | } else { | ||
129 | ws_name = join_args(argv + 2, argc - 2); | ||
88 | ws = workspace_by_name(ws_name); | 130 | ws = workspace_by_name(ws_name); |
89 | } | 131 | } |
90 | } | ||
91 | 132 | ||
92 | if (!ws) { | 133 | if (!no_auto_back_and_forth && config->auto_back_and_forth && |
93 | ws = workspace_create(NULL, ws_name); | 134 | prev_workspace_name) { |
94 | } | 135 | // auto back and forth move |
95 | free(ws_name); | 136 | if (old_ws->name && strcmp(old_ws->name, ws_name) == 0) { |
96 | struct sway_container *old_parent = current->parent; | 137 | // if target workspace is the current one |
97 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | 138 | free(ws_name); |
98 | struct sway_container *destination = seat_get_focus_inactive( | 139 | ws_name = strdup(prev_workspace_name); |
99 | config->handler_context.seat, ws); | 140 | ws = workspace_by_name(ws_name); |
100 | container_move_to(current, destination); | 141 | } |
101 | struct sway_container *focus = seat_get_focus_inactive( | 142 | } |
102 | config->handler_context.seat, old_parent); | ||
103 | seat_set_focus_warp(config->handler_context.seat, focus, true, false); | ||
104 | container_reap_empty(old_parent); | ||
105 | container_reap_empty(destination->parent); | ||
106 | |||
107 | // TODO: Ideally we would arrange the surviving parent after reaping, | ||
108 | // but container_reap_empty does not return it, so we arrange the | ||
109 | // workspace instead. | ||
110 | arrange_windows(old_ws); | ||
111 | arrange_windows(destination->parent); | ||
112 | 143 | ||
113 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 144 | if (!ws) { |
114 | } else if (strcasecmp(argv[1], "to") == 0 | 145 | ws = workspace_create(NULL, ws_name); |
115 | && strcasecmp(argv[2], "output") == 0) { | 146 | } |
116 | if (current->type == C_WORKSPACE) { | 147 | free(ws_name); |
117 | // TODO: Wrap children in a container and move that | ||
118 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | ||
119 | } else if (current->type != C_CONTAINER | ||
120 | && current->type != C_VIEW) { | ||
121 | return cmd_results_new(CMD_FAILURE, "move", | ||
122 | "Can only move containers and views."); | ||
123 | } | 148 | } |
149 | destination = seat_get_focus_inactive(config->handler_context.seat, ws); | ||
150 | } else if (strcasecmp(argv[1], "output") == 0) { | ||
124 | struct sway_container *source = container_parent(current, C_OUTPUT); | 151 | struct sway_container *source = container_parent(current, C_OUTPUT); |
125 | struct sway_container *destination = output_in_direction(argv[3], | 152 | struct sway_container *dest_output = output_in_direction(argv[2], |
126 | source->sway_output->wlr_output, current->x, current->y); | 153 | source->sway_output->wlr_output, current->x, current->y); |
127 | if (!destination) { | 154 | if (!dest_output) { |
128 | return cmd_results_new(CMD_FAILURE, "move workspace", | 155 | return cmd_results_new(CMD_FAILURE, "move workspace", |
129 | "Can't find output with name/direction '%s'", argv[3]); | 156 | "Can't find output with name/direction '%s'", argv[2]); |
130 | } | 157 | } |
131 | struct sway_container *focus = seat_get_focus_inactive( | 158 | destination = seat_get_focus_inactive( |
132 | config->handler_context.seat, destination); | 159 | config->handler_context.seat, dest_output); |
133 | if (!focus) { | 160 | if (!destination) { |
134 | // We've never been to this output before | 161 | // We've never been to this output before |
135 | focus = destination->children->items[0]; | 162 | destination = dest_output->children->items[0]; |
136 | } | 163 | } |
137 | struct sway_container *old_parent = current->parent; | 164 | } else if (strcasecmp(argv[1], "mark") == 0) { |
138 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | 165 | struct sway_view *dest_view = view_find_mark(argv[2]); |
139 | container_move_to(current, focus); | 166 | if (dest_view == NULL) { |
140 | seat_set_focus_warp(config->handler_context.seat, old_parent, true, false); | 167 | return cmd_results_new(CMD_FAILURE, "move", |
141 | container_reap_empty(old_parent); | 168 | "Mark '%s' not found", argv[2]); |
142 | container_reap_empty(focus->parent); | 169 | } |
143 | 170 | destination = dest_view->swayc; | |
144 | // TODO: Ideally we would arrange the surviving parent after reaping, | 171 | } else { |
145 | // but container_reap_empty does not return it, so we arrange the | 172 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
146 | // workspace instead. | ||
147 | arrange_windows(old_ws); | ||
148 | arrange_windows(focus->parent); | ||
149 | |||
150 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
151 | } | 173 | } |
152 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 174 | |
175 | // move container, arrange windows and return focus | ||
176 | container_move_to(current, destination); | ||
177 | struct sway_container *focus = | ||
178 | seat_get_focus_inactive(config->handler_context.seat, old_parent); | ||
179 | seat_set_focus_warp(config->handler_context.seat, focus, true, false); | ||
180 | container_reap_empty(old_parent); | ||
181 | container_reap_empty(destination->parent); | ||
182 | |||
183 | // TODO: Ideally we would arrange the surviving parent after reaping, | ||
184 | // but container_reap_empty does not return it, so we arrange the | ||
185 | // workspace instead. | ||
186 | arrange_windows(old_ws); | ||
187 | arrange_windows(destination->parent); | ||
188 | |||
189 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
153 | } | 190 | } |
154 | 191 | ||
155 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, | 192 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, |
156 | int argc, char **argv) { | 193 | int argc, char **argv) { |
157 | struct cmd_results *error = NULL; | 194 | struct cmd_results *error = NULL; |
158 | if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { | 195 | if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { |
159 | return error; | 196 | return error; |
160 | } else if (strcasecmp(argv[1], "to") != 0 | 197 | } |
161 | || strcasecmp(argv[2], "output") != 0) { | 198 | |
199 | while (strcasecmp(argv[1], "to") == 0) { | ||
200 | if (--argc < 3) { | ||
201 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
202 | } | ||
203 | ++argv; | ||
204 | } | ||
205 | |||
206 | if (strcasecmp(argv[1], "output") != 0) { | ||
162 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 207 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
163 | } | 208 | } |
209 | |||
164 | struct sway_container *source = container_parent(current, C_OUTPUT); | 210 | struct sway_container *source = container_parent(current, C_OUTPUT); |
165 | int center_x = current->width / 2 + current->x, | 211 | int center_x = current->width / 2 + current->x, |
166 | center_y = current->height / 2 + current->y; | 212 | center_y = current->height / 2 + current->y; |
167 | struct sway_container *destination = output_in_direction(argv[3], | 213 | struct sway_container *destination = output_in_direction(argv[2], |
168 | source->sway_output->wlr_output, center_x, center_y); | 214 | source->sway_output->wlr_output, center_x, center_y); |
169 | if (!destination) { | 215 | if (!destination) { |
170 | return cmd_results_new(CMD_FAILURE, "move workspace", | 216 | return cmd_results_new(CMD_FAILURE, "move workspace", |
171 | "Can't find output with name/direction '%s'", argv[3]); | 217 | "Can't find output with name/direction '%s'", argv[2]); |
172 | } | 218 | } |
173 | if (current->type != C_WORKSPACE) { | 219 | if (current->type != C_WORKSPACE) { |
174 | current = container_parent(current, C_WORKSPACE); | 220 | current = container_parent(current, C_WORKSPACE); |
@@ -242,9 +288,9 @@ static struct cmd_results *move_in_direction(struct sway_container *container, | |||
242 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 288 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
243 | } | 289 | } |
244 | 290 | ||
245 | static const char* expected_position_syntax = | 291 | static const char *expected_position_syntax = |
246 | "Expected 'move [absolute] position <x> <y>' or " | 292 | "Expected 'move [absolute] position <x> [px] <y> [px]' or " |
247 | "'move [absolute] position mouse'"; | 293 | "'move [absolute] position center|mouse'"; |
248 | 294 | ||
249 | static struct cmd_results *move_to_position(struct sway_container *container, | 295 | static struct cmd_results *move_to_position(struct sway_container *container, |
250 | int argc, char **argv) { | 296 | int argc, char **argv) { |
@@ -279,10 +325,18 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
279 | double ly = seat->cursor->cursor->y - container->height / 2; | 325 | double ly = seat->cursor->cursor->y - container->height / 2; |
280 | container_floating_move_to(container, lx, ly); | 326 | container_floating_move_to(container, lx, ly); |
281 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 327 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
328 | } else if (strcmp(argv[0], "center") == 0) { | ||
329 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | ||
330 | double lx = ws->x + (ws->width - container->width) / 2; | ||
331 | double ly = ws->y + (ws->height - container->height) / 2; | ||
332 | container_floating_move_to(container, lx, ly); | ||
333 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
282 | } | 334 | } |
283 | if (argc != 2) { | 335 | |
336 | if (argc < 2) { | ||
284 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | 337 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); |
285 | } | 338 | } |
339 | |||
286 | double lx, ly; | 340 | double lx, ly; |
287 | char *inv; | 341 | char *inv; |
288 | lx = (double)strtol(argv[0], &inv, 10); | 342 | lx = (double)strtol(argv[0], &inv, 10); |
@@ -290,11 +344,22 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
290 | return cmd_results_new(CMD_FAILURE, "move", | 344 | return cmd_results_new(CMD_FAILURE, "move", |
291 | "Invalid position specified"); | 345 | "Invalid position specified"); |
292 | } | 346 | } |
347 | if (strcmp(argv[1], "px") == 0) { | ||
348 | --argc; | ||
349 | ++argv; | ||
350 | } | ||
351 | |||
352 | if (argc > 3) { | ||
353 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | ||
354 | } | ||
355 | |||
293 | ly = (double)strtol(argv[1], &inv, 10); | 356 | ly = (double)strtol(argv[1], &inv, 10); |
294 | if (*inv != '\0' && strcasecmp(inv, "px") != 0) { | 357 | if ((*inv != '\0' && strcasecmp(inv, "px") != 0) || |
358 | (argc == 3 && strcmp(argv[2], "px") != 0)) { | ||
295 | return cmd_results_new(CMD_FAILURE, "move", | 359 | return cmd_results_new(CMD_FAILURE, "move", |
296 | "Invalid position specified"); | 360 | "Invalid position specified"); |
297 | } | 361 | } |
362 | |||
298 | container_floating_move_to(container, lx, ly); | 363 | container_floating_move_to(container, lx, ly); |
299 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 364 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
300 | } | 365 | } |
@@ -342,8 +407,11 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
342 | return move_in_direction(current, MOVE_UP, argc, argv); | 407 | return move_in_direction(current, MOVE_UP, argc, argv); |
343 | } else if (strcasecmp(argv[0], "down") == 0) { | 408 | } else if (strcasecmp(argv[0], "down") == 0) { |
344 | return move_in_direction(current, MOVE_DOWN, argc, argv); | 409 | return move_in_direction(current, MOVE_DOWN, argc, argv); |
345 | } else if (strcasecmp(argv[0], "container") == 0 | 410 | } else if ((strcasecmp(argv[0], "container") == 0 |
346 | || strcasecmp(argv[0], "window") == 0) { | 411 | || strcasecmp(argv[0], "window") == 0) || |
412 | (strcasecmp(argv[0], "--no-auto-back-and-forth") && | ||
413 | (strcasecmp(argv[0], "container") == 0 | ||
414 | || strcasecmp(argv[0], "window") == 0))) { | ||
347 | return cmd_move_container(current, argc, argv); | 415 | return cmd_move_container(current, argc, argv); |
348 | } else if (strcasecmp(argv[0], "workspace") == 0) { | 416 | } else if (strcasecmp(argv[0], "workspace") == 0) { |
349 | return cmd_move_workspace(current, argc, argv); | 417 | return cmd_move_workspace(current, argc, argv); |
diff --git a/sway/commands/rename.c b/sway/commands/rename.c index a380ff9c..c6952bbb 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c | |||
@@ -61,6 +61,16 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
61 | } | 61 | } |
62 | 62 | ||
63 | char *new_name = join_args(argv + argn, argc - argn); | 63 | char *new_name = join_args(argv + argn, argc - argn); |
64 | if (strcasecmp(new_name, "next") == 0 || | ||
65 | strcasecmp(new_name, "prev") == 0 || | ||
66 | strcasecmp(new_name, "next_on_output") == 0 || | ||
67 | strcasecmp(new_name, "prev_on_output") == 0 || | ||
68 | strcasecmp(new_name, "back_and_forth") == 0 || | ||
69 | strcasecmp(new_name, "current") == 0) { | ||
70 | free(new_name); | ||
71 | return cmd_results_new(CMD_INVALID, "rename", | ||
72 | "Cannot use special workspace name '%s'", argv[argn]); | ||
73 | } | ||
64 | struct sway_container *tmp_workspace = workspace_by_name(new_name); | 74 | struct sway_container *tmp_workspace = workspace_by_name(new_name); |
65 | if (tmp_workspace) { | 75 | if (tmp_workspace) { |
66 | free(new_name); | 76 | free(new_name); |
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index e8b37182..f5558bb4 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -17,17 +17,6 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
17 | 17 | ||
18 | int output_location = -1; | 18 | int output_location = -1; |
19 | 19 | ||
20 | struct sway_container *current_container = config->handler_context.current_container; | ||
21 | struct sway_container *old_workspace = NULL, *old_output = NULL; | ||
22 | if (current_container) { | ||
23 | if (current_container->type == C_WORKSPACE) { | ||
24 | old_workspace = current_container; | ||
25 | } else { | ||
26 | old_workspace = container_parent(current_container, C_WORKSPACE); | ||
27 | } | ||
28 | old_output = container_parent(current_container, C_OUTPUT); | ||
29 | } | ||
30 | |||
31 | for (int i = 0; i < argc; ++i) { | 20 | for (int i = 0; i < argc; ++i) { |
32 | if (strcasecmp(argv[i], "output") == 0) { | 21 | if (strcasecmp(argv[i], "output") == 0) { |
33 | output_location = i; | 22 | output_location = i; |
@@ -57,29 +46,36 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
57 | if (config->reading || !config->active) { | 46 | if (config->reading || !config->active) { |
58 | return cmd_results_new(CMD_DEFER, "workspace", NULL); | 47 | return cmd_results_new(CMD_DEFER, "workspace", NULL); |
59 | } | 48 | } |
49 | |||
50 | bool no_auto_back_and_forth = false; | ||
51 | while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) { | ||
52 | no_auto_back_and_forth = true; | ||
53 | if ((error = checkarg(--argc, "workspace", EXPECTED_AT_LEAST, 1))) { | ||
54 | return error; | ||
55 | } | ||
56 | ++argv; | ||
57 | } | ||
58 | |||
59 | |||
60 | struct sway_container *ws = NULL; | 60 | struct sway_container *ws = NULL; |
61 | if (strcasecmp(argv[0], "number") == 0) { | 61 | if (strcasecmp(argv[0], "number") == 0) { |
62 | if (argc < 2) { | ||
63 | cmd_results_new(CMD_INVALID, "workspace", | ||
64 | "Expected workspace number"); | ||
65 | } | ||
62 | if (!(ws = workspace_by_number(argv[1]))) { | 66 | if (!(ws = workspace_by_number(argv[1]))) { |
63 | char *name = join_args(argv + 1, argc - 1); | 67 | char *name = join_args(argv + 1, argc - 1); |
64 | ws = workspace_create(NULL, name); | 68 | ws = workspace_create(NULL, name); |
65 | free(name); | 69 | free(name); |
66 | } | 70 | } |
67 | } else if (strcasecmp(argv[0], "next") == 0) { | 71 | } else if (strcasecmp(argv[0], "next") == 0 || |
68 | ws = workspace_next(old_workspace); | 72 | strcasecmp(argv[0], "prev") == 0 || |
69 | } else if (strcasecmp(argv[0], "prev") == 0) { | 73 | strcasecmp(argv[0], "next_on_output") == 0 || |
70 | ws = workspace_prev(old_workspace); | 74 | strcasecmp(argv[0], "prev_on_output") == 0 || |
71 | } else if (strcasecmp(argv[0], "next_on_output") == 0) { | 75 | strcasecmp(argv[0], "current") == 0) { |
72 | ws = workspace_output_next(old_output); | 76 | ws = workspace_by_name(argv[0]); |
73 | } else if (strcasecmp(argv[0], "prev_on_output") == 0) { | ||
74 | ws = workspace_output_prev(old_output); | ||
75 | } else if (strcasecmp(argv[0], "back_and_forth") == 0) { | 77 | } else if (strcasecmp(argv[0], "back_and_forth") == 0) { |
76 | // if auto_back_and_forth is enabled, workspace_switch will swap | 78 | if (!(ws = workspace_by_name(argv[0])) && prev_workspace_name) { |
77 | // the workspaces. If we created prev_workspace here, workspace_switch | ||
78 | // would put us back on original workspace. | ||
79 | if (config->auto_back_and_forth) { | ||
80 | ws = old_workspace; | ||
81 | } else if (prev_workspace_name | ||
82 | && !(ws = workspace_by_name(prev_workspace_name))) { | ||
83 | ws = workspace_create(NULL, prev_workspace_name); | 79 | ws = workspace_create(NULL, prev_workspace_name); |
84 | } | 80 | } |
85 | } else { | 81 | } else { |
@@ -89,7 +85,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
89 | } | 85 | } |
90 | free(name); | 86 | free(name); |
91 | } | 87 | } |
92 | workspace_switch(ws); | 88 | workspace_switch(ws, no_auto_back_and_forth); |
93 | } | 89 | } |
94 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 90 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
95 | } | 91 | } |
diff --git a/sway/criteria.c b/sway/criteria.c index 39d300ea..9077aa9b 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -361,8 +361,17 @@ static char *get_focused_prop(enum criteria_token token) { | |||
361 | } | 361 | } |
362 | } | 362 | } |
363 | break; | 363 | break; |
364 | case T_CON_ID: // These do not support __focused__ | 364 | case T_CON_ID: |
365 | case T_CON_MARK: | 365 | if (view->swayc == NULL) { |
366 | return NULL; | ||
367 | } | ||
368 | size_t id = view->swayc->id; | ||
369 | size_t id_size = snprintf(NULL, 0, "%zu", id) + 1; | ||
370 | char *id_str = malloc(id_size); | ||
371 | snprintf(id_str, id_size, "%zu", id); | ||
372 | value = id_str; | ||
373 | break; | ||
374 | case T_CON_MARK: // These do not support __focused__ | ||
366 | case T_FLOATING: | 375 | case T_FLOATING: |
367 | #ifdef HAVE_XWAYLAND | 376 | #ifdef HAVE_XWAYLAND |
368 | case T_ID: | 377 | case T_ID: |
@@ -425,7 +434,7 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { | |||
425 | case T_CON_ID: | 434 | case T_CON_ID: |
426 | criteria->con_id = strtoul(effective_value, &endptr, 10); | 435 | criteria->con_id = strtoul(effective_value, &endptr, 10); |
427 | if (*endptr != 0) { | 436 | if (*endptr != 0) { |
428 | error = strdup("The value for 'con_id' should be numeric"); | 437 | error = strdup("The value for 'con_id' should be '__focused__' or numeric"); |
429 | } | 438 | } |
430 | break; | 439 | break; |
431 | case T_CON_MARK: | 440 | case T_CON_MARK: |
@@ -452,13 +461,18 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { | |||
452 | criteria->tiling = true; | 461 | criteria->tiling = true; |
453 | break; | 462 | break; |
454 | case T_URGENT: | 463 | case T_URGENT: |
455 | if (strcmp(effective_value, "latest") == 0) { | 464 | if (strcmp(effective_value, "latest") == 0 || |
465 | strcmp(effective_value, "newest") == 0 || | ||
466 | strcmp(effective_value, "last") == 0 || | ||
467 | strcmp(effective_value, "recent") == 0) { | ||
456 | criteria->urgent = 'l'; | 468 | criteria->urgent = 'l'; |
457 | } else if (strcmp(effective_value, "oldest") == 0) { | 469 | } else if (strcmp(effective_value, "oldest") == 0 || |
470 | strcmp(effective_value, "first") == 0) { | ||
458 | criteria->urgent = 'o'; | 471 | criteria->urgent = 'o'; |
459 | } else { | 472 | } else { |
460 | error = | 473 | error = |
461 | strdup("The value for 'urgent' must be 'latest' or 'oldest'"); | 474 | strdup("The value for 'urgent' must be 'first', 'last', " |
475 | "'latest', 'newest', 'oldest' or 'recent'"); | ||
462 | } | 476 | } |
463 | break; | 477 | break; |
464 | case T_WORKSPACE: | 478 | case T_WORKSPACE: |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 82df38e3..73a01152 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -84,6 +84,9 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | |||
84 | *floating* enable|disable|toggle | 84 | *floating* enable|disable|toggle |
85 | Make focused view floating, non-floating, or the opposite of what it is now. | 85 | Make focused view floating, non-floating, or the opposite of what it is now. |
86 | 86 | ||
87 | <criteria> *focus* | ||
88 | Moves focus to the container that matches the specified criteria. | ||
89 | |||
87 | *focus* up|right|down|left | 90 | *focus* up|right|down|left |
88 | Moves focus to the next container in the specified direction. | 91 | Moves focus to the next container in the specified direction. |
89 | 92 | ||
@@ -111,33 +114,53 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | |||
111 | *fullscreen* | 114 | *fullscreen* |
112 | Toggles fullscreen for the focused view. | 115 | Toggles fullscreen for the focused view. |
113 | 116 | ||
114 | *layout* splith|splitv|stacking|tabbed | 117 | *layout* default|splith|splitv|stacking|tabbed |
115 | Sets the layout mode of the focused container. | 118 | Sets the layout mode of the focused container. |
116 | 119 | ||
117 | *layout* toggle split | 120 | *layout* toggle [split|all] |
118 | Switches the focused container between the splitv and splith layouts. | 121 | Cycles the layout mode of the focused container though a preset list of |
122 | layouts. If no argument is given, then it cycles through stacking, tabbed | ||
123 | and the last split layout. If "split" is given, then it cycles through | ||
124 | splith and splitv. If "all" is given, then it cycles through every layout. | ||
125 | |||
126 | *layout* toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]... | ||
127 | Cycles the layout mode of the focused container through a list of layouts. | ||
119 | 128 | ||
120 | *move* left|right|up|down [<px>] | 129 | *move* left|right|up|down [<px> px] |
121 | Moves the focused container in the direction specified. If the container, | 130 | Moves the focused container in the direction specified. If the container, |
122 | the optional _px_ argument specifies how many pixels to move the container. | 131 | the optional _px_ argument specifies how many pixels to move the container. |
123 | If unspecified, the default is 10 pixels. Pixels are ignored when moving | 132 | If unspecified, the default is 10 pixels. Pixels are ignored when moving |
124 | tiled containers. | 133 | tiled containers. |
125 | 134 | ||
126 | *move* container|window to workspace <name> | 135 | *move* [absolute] position <pos_x> [px] <pos_y> [px] |
127 | Moves the focused container to the specified workspace. | 136 | Moves the focused container to the specified position. |
128 | 137 | ||
129 | *move* container|window to workspace prev|next | 138 | *move* [absolute] position center|mouse |
130 | Moves the focused container to the previous or next workspace on this | 139 | Moves the focused container to be centered on the workspace or mouse. |
131 | output, or if no workspaces remain, the previous or next output. | 140 | |
141 | *move* container|window [to] mark <mark> | ||
142 | Moves the focused container to the specified mark. | ||
143 | |||
144 | *move* [--no-auto-back-and-forth] container|window [to] workspace [number] <name> | ||
145 | Moves the focused container to the specified workspace. The string "number" | ||
146 | is optional and is used to match a workspace with the same number, even if | ||
147 | it has a different name. | ||
132 | 148 | ||
133 | *move* container|window to workspace prev\_on\_output|next\_on\_output | 149 | *move* container|window [to] workspace prev|next|current |
150 | Moves the focused container to the previous, next or current workspace on | ||
151 | this output, or if no workspaces remain, the previous or next output. | ||
152 | |||
153 | *move* container|window [to] workspace prev\_on\_output|next\_on\_output | ||
134 | Moves the focused container to the previous or next workspace on this | 154 | Moves the focused container to the previous or next workspace on this |
135 | output, wrapping around if already at the first or last workspace. | 155 | output, wrapping around if already at the first or last workspace. |
136 | 156 | ||
137 | *move* container|window|workspace to output <name> | 157 | *move* container|window [to] workspace back_and_forth |
158 | Moves the focused container to previously focused workspace. | ||
159 | |||
160 | *move* container|window|workspace [to] output <name> | ||
138 | Moves the focused container or workspace to the specified output. | 161 | Moves the focused container or workspace to the specified output. |
139 | 162 | ||
140 | *move* container|window|workspace to output up|right|down|left | 163 | *move* container|window|workspace [to] output up|right|down|left |
141 | Moves the focused container or workspace to next output in the specified | 164 | Moves the focused container or workspace to next output in the specified |
142 | direction. | 165 | direction. |
143 | 166 | ||
@@ -511,7 +534,7 @@ config after the others, or it will be matched instead of the others. | |||
511 | state. Using _allow_ or _deny_ controls the window's ability to set itself | 534 | state. Using _allow_ or _deny_ controls the window's ability to set itself |
512 | as urgent. By default, windows are allowed to set their own urgency. | 535 | as urgent. By default, windows are allowed to set their own urgency. |
513 | 536 | ||
514 | *workspace* [number] <name> | 537 | *workspace* [--no-auto-back-and-forth] [number] <name> |
515 | Switches to the specified workspace. The string "number" is optional and is | 538 | Switches to the specified workspace. The string "number" is optional and is |
516 | used to sort workspaces. | 539 | used to sort workspaces. |
517 | 540 | ||
@@ -522,6 +545,9 @@ config after the others, or it will be matched instead of the others. | |||
522 | *workspace* prev\_on\_output|next\_on\_output | 545 | *workspace* prev\_on\_output|next\_on\_output |
523 | Switches to the next workspace on the current output. | 546 | Switches to the next workspace on the current output. |
524 | 547 | ||
548 | *workspace* back_and_forth | ||
549 | Switches to the previously focused workspace. | ||
550 | |||
525 | *workspace* <name> output <output> | 551 | *workspace* <name> output <output> |
526 | Specifies that workspace _name_ should be shown on the specified _output_. | 552 | Specifies that workspace _name_ should be shown on the specified _output_. |
527 | 553 | ||
@@ -582,7 +608,9 @@ The following attributes may be matched with: | |||
582 | the currently focused window. | 608 | the currently focused window. |
583 | 609 | ||
584 | *con\_id* | 610 | *con\_id* |
585 | Compare against the internal container ID, which you can find via IPC. | 611 | Compare against the internal container ID, which you can find via IPC. If |
612 | value is \_\_focused\_\_, then the id must be the same as that of the | ||
613 | currently focused window. | ||
586 | 614 | ||
587 | *con\_mark* | 615 | *con\_mark* |
588 | Compare against the window marks. Can be a regular expression. | 616 | Compare against the window marks. Can be a regular expression. |
@@ -612,7 +640,8 @@ The following attributes may be matched with: | |||
612 | currently focused window. | 640 | currently focused window. |
613 | 641 | ||
614 | *urgent* | 642 | *urgent* |
615 | Compares the urgent state of the window. Can be "latest" or "oldest". | 643 | Compares the urgent state of the window. Can be "first", "last", "latest", |
644 | "newest", "oldest" or "recent". | ||
616 | 645 | ||
617 | *window\_role* | 646 | *window\_role* |
618 | Compare against the window role (WM\_WINDOW\_ROLE). Can be a regular | 647 | Compare against the window role (WM\_WINDOW\_ROLE). Can be a regular |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 07de9664..28cdc71e 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -859,7 +859,7 @@ struct sway_container *container_split(struct sway_container *child, | |||
859 | } | 859 | } |
860 | if (child->type == C_WORKSPACE && child->children->length == 0) { | 860 | if (child->type == C_WORKSPACE && child->children->length == 0) { |
861 | // Special case: this just behaves like splitt | 861 | // Special case: this just behaves like splitt |
862 | child->prev_layout = child->layout; | 862 | child->prev_split_layout = child->layout; |
863 | child->layout = layout; | 863 | child->layout = layout; |
864 | return child; | 864 | return child; |
865 | } | 865 | } |
@@ -870,7 +870,7 @@ struct sway_container *container_split(struct sway_container *child, | |||
870 | 870 | ||
871 | remove_gaps(child); | 871 | remove_gaps(child); |
872 | 872 | ||
873 | cont->prev_layout = L_NONE; | 873 | cont->prev_split_layout = L_NONE; |
874 | cont->width = child->width; | 874 | cont->width = child->width; |
875 | cont->height = child->height; | 875 | cont->height = child->height; |
876 | cont->x = child->x; | 876 | cont->x = child->x; |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 9465b3a1..faaa53a1 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <strings.h> | ||
3 | #include <wayland-server.h> | 4 | #include <wayland-server.h> |
4 | #include <wlr/render/wlr_renderer.h> | 5 | #include <wlr/render/wlr_renderer.h> |
5 | #include <wlr/types/wlr_buffer.h> | 6 | #include <wlr/types/wlr_buffer.h> |
@@ -456,7 +457,13 @@ static struct sway_container *select_workspace(struct sway_view *view) { | |||
456 | if (criteria->type == CT_ASSIGN_WORKSPACE) { | 457 | if (criteria->type == CT_ASSIGN_WORKSPACE) { |
457 | ws = workspace_by_name(criteria->target); | 458 | ws = workspace_by_name(criteria->target); |
458 | if (!ws) { | 459 | if (!ws) { |
459 | ws = workspace_create(NULL, criteria->target); | 460 | if (strcasecmp(criteria->target, "back_and_forth") == 0) { |
461 | if (prev_workspace_name) { | ||
462 | ws = workspace_create(NULL, prev_workspace_name); | ||
463 | } | ||
464 | } else { | ||
465 | ws = workspace_create(NULL, criteria->target); | ||
466 | } | ||
460 | } | 467 | } |
461 | break; | 468 | break; |
462 | } else { | 469 | } else { |
@@ -891,6 +898,15 @@ static bool find_by_mark_iterator(struct sway_container *con, | |||
891 | return con->type == C_VIEW && view_has_mark(con->sway_view, mark); | 898 | return con->type == C_VIEW && view_has_mark(con->sway_view, mark); |
892 | } | 899 | } |
893 | 900 | ||
901 | struct sway_view *view_find_mark(char *mark) { | ||
902 | struct sway_container *container = container_find(&root_container, | ||
903 | find_by_mark_iterator, mark); | ||
904 | if (!container) { | ||
905 | return NULL; | ||
906 | } | ||
907 | return container->sway_view; | ||
908 | } | ||
909 | |||
894 | bool view_find_and_unmark(char *mark) { | 910 | bool view_find_and_unmark(char *mark) { |
895 | struct sway_container *container = container_find(&root_container, | 911 | struct sway_container *container = container_find(&root_container, |
896 | find_by_mark_iterator, mark); | 912 | find_by_mark_iterator, mark); |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index cc225e79..3fcad631 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -59,7 +59,7 @@ struct sway_container *workspace_create(struct sway_container *output, | |||
59 | workspace->width = output->width; | 59 | workspace->width = output->width; |
60 | workspace->height = output->height; | 60 | workspace->height = output->height; |
61 | workspace->name = !name ? NULL : strdup(name); | 61 | workspace->name = !name ? NULL : strdup(name); |
62 | workspace->prev_layout = L_NONE; | 62 | workspace->prev_split_layout = L_NONE; |
63 | workspace->layout = container_get_default_layout(output); | 63 | workspace->layout = container_get_default_layout(output); |
64 | 64 | ||
65 | struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); | 65 | struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); |
@@ -250,6 +250,7 @@ struct sway_container *workspace_by_name(const char *name) { | |||
250 | current_workspace = container_parent(focus, C_WORKSPACE); | 250 | current_workspace = container_parent(focus, C_WORKSPACE); |
251 | current_output = container_parent(focus, C_OUTPUT); | 251 | current_output = container_parent(focus, C_OUTPUT); |
252 | } | 252 | } |
253 | |||
253 | if (strcmp(name, "prev") == 0) { | 254 | if (strcmp(name, "prev") == 0) { |
254 | return workspace_prev(current_workspace); | 255 | return workspace_prev(current_workspace); |
255 | } else if (strcmp(name, "prev_on_output") == 0) { | 256 | } else if (strcmp(name, "prev_on_output") == 0) { |
@@ -260,6 +261,9 @@ struct sway_container *workspace_by_name(const char *name) { | |||
260 | return workspace_output_next(current_output); | 261 | return workspace_output_next(current_output); |
261 | } else if (strcmp(name, "current") == 0) { | 262 | } else if (strcmp(name, "current") == 0) { |
262 | return current_workspace; | 263 | return current_workspace; |
264 | } else if (strcasecmp(name, "back_and_forth") == 0) { | ||
265 | return prev_workspace_name ? container_find(&root_container, | ||
266 | _workspace_by_name, (void *)prev_workspace_name) : NULL; | ||
263 | } else { | 267 | } else { |
264 | return container_find(&root_container, _workspace_by_name, | 268 | return container_find(&root_container, _workspace_by_name, |
265 | (void *)name); | 269 | (void *)name); |
@@ -364,7 +368,8 @@ struct sway_container *workspace_prev(struct sway_container *current) { | |||
364 | return workspace_prev_next_impl(current, false); | 368 | return workspace_prev_next_impl(current, false); |
365 | } | 369 | } |
366 | 370 | ||
367 | bool workspace_switch(struct sway_container *workspace) { | 371 | bool workspace_switch(struct sway_container *workspace, |
372 | bool no_auto_back_and_forth) { | ||
368 | if (!workspace) { | 373 | if (!workspace) { |
369 | return false; | 374 | return false; |
370 | } | 375 | } |
@@ -379,7 +384,7 @@ bool workspace_switch(struct sway_container *workspace) { | |||
379 | active_ws = container_parent(focus, C_WORKSPACE); | 384 | active_ws = container_parent(focus, C_WORKSPACE); |
380 | } | 385 | } |
381 | 386 | ||
382 | if (config->auto_back_and_forth | 387 | if (!no_auto_back_and_forth && config->auto_back_and_forth |
383 | && active_ws == workspace | 388 | && active_ws == workspace |
384 | && prev_workspace_name) { | 389 | && prev_workspace_name) { |
385 | struct sway_container *new_ws = workspace_by_name(prev_workspace_name); | 390 | struct sway_container *new_ws = workspace_by_name(prev_workspace_name); |