diff options
author | Brian Ashworth <RedSoxFan@users.noreply.github.com> | 2018-08-06 11:47:00 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-06 11:47:00 -0400 |
commit | 639f3368e101b697aaf3715b1213ea30766ff4ed (patch) | |
tree | 67dfb7bc19eb3dd27252d8b0f493436250b4fdea | |
parent | Move workspace moving code out of container_move_to (diff) | |
parent | Merge pull request #2268 from emersion/server-decoration-borders (diff) | |
download | sway-639f3368e101b697aaf3715b1213ea30766ff4ed.tar.gz sway-639f3368e101b697aaf3715b1213ea30766ff4ed.tar.zst sway-639f3368e101b697aaf3715b1213ea30766ff4ed.zip |
Merge branch 'master' into workspace-move-to-output
-rw-r--r-- | include/sway/decoration.h | 17 | ||||
-rw-r--r-- | include/sway/server.h | 11 | ||||
-rw-r--r-- | include/sway/tree/container.h | 2 | ||||
-rw-r--r-- | include/sway/tree/view.h | 9 | ||||
-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/decoration.c | 71 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 19 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 25 | ||||
-rw-r--r-- | sway/meson.build | 5 | ||||
-rw-r--r-- | sway/server.c | 12 | ||||
-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 |
19 files changed, 531 insertions, 189 deletions
diff --git a/include/sway/decoration.h b/include/sway/decoration.h new file mode 100644 index 00000000..7916746e --- /dev/null +++ b/include/sway/decoration.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef _SWAY_DECORATION_H | ||
2 | #define _SWAY_DECORATION_H | ||
3 | |||
4 | #include <wlr/types/wlr_server_decoration.h> | ||
5 | |||
6 | struct sway_server_decoration { | ||
7 | struct wlr_server_decoration *wlr_server_decoration; | ||
8 | struct wl_list link; | ||
9 | |||
10 | struct wl_listener destroy; | ||
11 | struct wl_listener mode; | ||
12 | }; | ||
13 | |||
14 | struct sway_server_decoration *decoration_from_surface( | ||
15 | struct wlr_surface *surface); | ||
16 | |||
17 | #endif | ||
diff --git a/include/sway/server.h b/include/sway/server.h index a3782f91..b93584b6 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -4,12 +4,13 @@ | |||
4 | #include <wayland-server.h> | 4 | #include <wayland-server.h> |
5 | #include <wlr/backend.h> | 5 | #include <wlr/backend.h> |
6 | #include <wlr/backend/session.h> | 6 | #include <wlr/backend/session.h> |
7 | #include <wlr/render/wlr_renderer.h> | ||
7 | #include <wlr/types/wlr_compositor.h> | 8 | #include <wlr/types/wlr_compositor.h> |
8 | #include <wlr/types/wlr_data_device.h> | 9 | #include <wlr/types/wlr_data_device.h> |
9 | #include <wlr/types/wlr_layer_shell.h> | 10 | #include <wlr/types/wlr_layer_shell.h> |
11 | #include <wlr/types/wlr_server_decoration.h> | ||
10 | #include <wlr/types/wlr_xdg_shell_v6.h> | 12 | #include <wlr/types/wlr_xdg_shell_v6.h> |
11 | #include <wlr/types/wlr_xdg_shell.h> | 13 | #include <wlr/types/wlr_xdg_shell.h> |
12 | #include <wlr/render/wlr_renderer.h> | ||
13 | // TODO WLR: make Xwayland optional | 14 | // TODO WLR: make Xwayland optional |
14 | #include "list.h" | 15 | #include "list.h" |
15 | #include "config.h" | 16 | #include "config.h" |
@@ -42,11 +43,17 @@ struct sway_server { | |||
42 | 43 | ||
43 | struct wlr_xdg_shell *xdg_shell; | 44 | struct wlr_xdg_shell *xdg_shell; |
44 | struct wl_listener xdg_shell_surface; | 45 | struct wl_listener xdg_shell_surface; |
46 | |||
45 | #ifdef HAVE_XWAYLAND | 47 | #ifdef HAVE_XWAYLAND |
46 | struct sway_xwayland xwayland; | 48 | struct sway_xwayland xwayland; |
47 | struct wl_listener xwayland_surface; | 49 | struct wl_listener xwayland_surface; |
48 | struct wl_listener xwayland_ready; | 50 | struct wl_listener xwayland_ready; |
49 | #endif | 51 | #endif |
52 | |||
53 | struct wlr_server_decoration_manager *server_decoration_manager; | ||
54 | struct wl_listener server_decoration; | ||
55 | struct wl_list decorations; // sway_server_decoration::link | ||
56 | |||
50 | bool debug_txn_timings; | 57 | bool debug_txn_timings; |
51 | 58 | ||
52 | list_t *transactions; | 59 | list_t *transactions; |
@@ -71,4 +78,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data); | |||
71 | #ifdef HAVE_XWAYLAND | 78 | #ifdef HAVE_XWAYLAND |
72 | void handle_xwayland_surface(struct wl_listener *listener, void *data); | 79 | void handle_xwayland_surface(struct wl_listener *listener, void *data); |
73 | #endif | 80 | #endif |
81 | void handle_server_decoration(struct wl_listener *listener, void *data); | ||
82 | |||
74 | #endif | 83 | #endif |
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 37fd02bc..c2225bcb 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -118,6 +118,8 @@ struct sway_view { | |||
118 | struct sway_xdg_shell_v6_view { | 118 | struct sway_xdg_shell_v6_view { |
119 | struct sway_view view; | 119 | struct sway_view view; |
120 | 120 | ||
121 | enum wlr_server_decoration_manager_mode deco_mode; | ||
122 | |||
121 | struct wl_listener commit; | 123 | struct wl_listener commit; |
122 | struct wl_listener request_move; | 124 | struct wl_listener request_move; |
123 | struct wl_listener request_resize; | 125 | struct wl_listener request_resize; |
@@ -134,6 +136,8 @@ struct sway_xdg_shell_v6_view { | |||
134 | struct sway_xdg_shell_view { | 136 | struct sway_xdg_shell_view { |
135 | struct sway_view view; | 137 | struct sway_view view; |
136 | 138 | ||
139 | enum wlr_server_decoration_manager_mode deco_mode; | ||
140 | |||
137 | struct wl_listener commit; | 141 | struct wl_listener commit; |
138 | struct wl_listener request_move; | 142 | struct wl_listener request_move; |
139 | struct wl_listener request_resize; | 143 | struct wl_listener request_resize; |
@@ -316,6 +320,11 @@ void view_update_title(struct sway_view *view, bool force); | |||
316 | void view_execute_criteria(struct sway_view *view); | 320 | void view_execute_criteria(struct sway_view *view); |
317 | 321 | ||
318 | /** | 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 | /** | ||
319 | * 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. |
320 | * Returns true if it matched a view. | 329 | * Returns true if it matched a view. |
321 | */ | 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 1af98e1f..bb4a7124 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> |
@@ -18,11 +19,11 @@ | |||
18 | #include "list.h" | 19 | #include "list.h" |
19 | #include "log.h" | 20 | #include "log.h" |
20 | 21 | ||
21 | static const char* expected_syntax = | 22 | static const char *expected_syntax = |
22 | "Expected 'move <left|right|up|down> <[px] px>' or " | 23 | "Expected 'move <left|right|up|down> <[px] px>' or " |
23 | "'move <container|window> to workspace <name>' or " | 24 | "'move [--no-auto-back-and-forth] <container|window> [to] workspace <name>' or " |
24 | "'move <container|window|workspace> to output <name|direction>' or " | 25 | "'move [--no-auto-back-and-forth] <container|window|workspace> [to] output <name|direction>' or " |
25 | "'move position mouse'"; | 26 | "'move <container|window> [to] mark <mark>'"; |
26 | 27 | ||
27 | static struct sway_container *output_in_direction(const char *direction, | 28 | static struct sway_container *output_in_direction(const char *direction, |
28 | struct wlr_output *reference, int ref_lx, int ref_ly) { | 29 | struct wlr_output *reference, int ref_lx, int ref_ly) { |
@@ -54,104 +55,140 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
54 | int argc, char **argv) { | 55 | int argc, char **argv) { |
55 | struct cmd_results *error = NULL; | 56 | struct cmd_results *error = NULL; |
56 | if ((error = checkarg(argc, "move container/window", | 57 | if ((error = checkarg(argc, "move container/window", |
57 | EXPECTED_AT_LEAST, 4))) { | 58 | EXPECTED_AT_LEAST, 3))) { |
58 | return error; | 59 | return error; |
59 | } else if (strcasecmp(argv[1], "to") == 0 | 60 | } |
60 | && strcasecmp(argv[2], "workspace") == 0) { | 61 | |
61 | // move container to workspace x | 62 | if (current->type == C_WORKSPACE) { |
62 | if (current->type == C_WORKSPACE) { | 63 | if (current->children->length == 0) { |
63 | if (current->children->length == 0) { | ||
64 | return cmd_results_new(CMD_FAILURE, "move", | ||
65 | "Can't move an empty workspace"); | ||
66 | } | ||
67 | current = container_wrap_children(current); | ||
68 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { | ||
69 | return cmd_results_new(CMD_FAILURE, "move", | 64 | return cmd_results_new(CMD_FAILURE, "move", |
70 | "Can only move containers and views."); | 65 | "Can't move an empty workspace"); |
71 | } | 66 | } |
72 | struct sway_container *ws; | 67 | current = container_wrap_children(current); |
73 | char *ws_name = NULL; | 68 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { |
74 | if (argc == 5 && strcasecmp(argv[3], "number") == 0) { | 69 | return cmd_results_new(CMD_FAILURE, "move", |
75 | // move "container to workspace number x" | 70 | "Can only move containers and views."); |
76 | ws_name = strdup(argv[4]); | 71 | } |
77 | ws = workspace_by_number(ws_name); | 72 | |
78 | } else { | 73 | bool no_auto_back_and_forth = false; |
79 | ws_name = join_args(argv + 3, argc - 3); | 74 | while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) { |
80 | ws = workspace_by_name(ws_name); | 75 | no_auto_back_and_forth = true; |
76 | if (--argc < 3) { | ||
77 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
78 | } | ||
79 | ++argv; | ||
80 | } | ||
81 | while (strcasecmp(argv[1], "--no-auto-back-and-forth") == 0) { | ||
82 | no_auto_back_and_forth = true; | ||
83 | if (--argc < 3) { | ||
84 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
81 | } | 85 | } |
86 | argv++; | ||
87 | } | ||
88 | |||
89 | while (strcasecmp(argv[1], "to") == 0) { | ||
90 | if (--argc < 3) { | ||
91 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
92 | } | ||
93 | argv++; | ||
94 | } | ||
82 | 95 | ||
83 | if (config->auto_back_and_forth && prev_workspace_name) { | 96 | struct sway_container *old_parent = current->parent; |
84 | // auto back and forth move | 97 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); |
85 | struct sway_container *curr_ws = container_parent(current, C_WORKSPACE); | 98 | struct sway_container *destination = NULL; |
86 | if (curr_ws->name && strcmp(curr_ws->name, ws_name) == 0) { | 99 | |
87 | // if target workspace is the current one | 100 | // determine destination |
88 | free(ws_name); | 101 | if (strcasecmp(argv[1], "workspace") == 0) { |
89 | ws_name = strdup(prev_workspace_name); | 102 | // move container to workspace x |
103 | struct sway_container *ws; | ||
104 | if (strcasecmp(argv[2], "next") == 0 || | ||
105 | strcasecmp(argv[2], "prev") == 0 || | ||
106 | strcasecmp(argv[2], "next_on_output") == 0 || | ||
107 | strcasecmp(argv[2], "prev_on_output") == 0 || | ||
108 | strcasecmp(argv[2], "back_and_forth") == 0 || | ||
109 | strcasecmp(argv[2], "current") == 0) { | ||
110 | ws = workspace_by_name(argv[2]); | ||
111 | } else if (strcasecmp(argv[2], "back_and_forth") == 0) { | ||
112 | if (!(ws = workspace_by_name(argv[2]))) { | ||
113 | if (prev_workspace_name) { | ||
114 | ws = workspace_create(NULL, prev_workspace_name); | ||
115 | } else { | ||
116 | return cmd_results_new(CMD_FAILURE, "move", | ||
117 | "No workspace was previously active."); | ||
118 | } | ||
119 | } | ||
120 | } else { | ||
121 | char *ws_name = NULL; | ||
122 | if (strcasecmp(argv[2], "number") == 0) { | ||
123 | // move "container to workspace number x" | ||
124 | if (argc < 4) { | ||
125 | return cmd_results_new(CMD_INVALID, "move", | ||
126 | expected_syntax); | ||
127 | } | ||
128 | ws_name = strdup(argv[3]); | ||
129 | ws = workspace_by_number(ws_name); | ||
130 | } else { | ||
131 | ws_name = join_args(argv + 2, argc - 2); | ||
90 | ws = workspace_by_name(ws_name); | 132 | ws = workspace_by_name(ws_name); |
91 | } | 133 | } |
92 | } | ||
93 | 134 | ||
94 | if (!ws) { | 135 | if (!no_auto_back_and_forth && config->auto_back_and_forth && |
95 | ws = workspace_create(NULL, ws_name); | 136 | prev_workspace_name) { |
96 | } | 137 | // auto back and forth move |
97 | free(ws_name); | 138 | if (old_ws->name && strcmp(old_ws->name, ws_name) == 0) { |
98 | struct sway_container *old_parent = current->parent; | 139 | // if target workspace is the current one |
99 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | 140 | free(ws_name); |
100 | struct sway_container *destination = seat_get_focus_inactive( | 141 | ws_name = strdup(prev_workspace_name); |
101 | config->handler_context.seat, ws); | 142 | ws = workspace_by_name(ws_name); |
102 | container_move_to(current, destination); | 143 | } |
103 | struct sway_container *focus = seat_get_focus_inactive( | 144 | } |
104 | config->handler_context.seat, old_parent); | ||
105 | seat_set_focus_warp(config->handler_context.seat, focus, true, false); | ||
106 | container_reap_empty(old_parent); | ||
107 | container_reap_empty(destination->parent); | ||
108 | |||
109 | // TODO: Ideally we would arrange the surviving parent after reaping, | ||
110 | // but container_reap_empty does not return it, so we arrange the | ||
111 | // workspace instead. | ||
112 | arrange_windows(old_ws); | ||
113 | arrange_windows(destination->parent); | ||
114 | 145 | ||
115 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 146 | if (!ws) { |
116 | } else if (strcasecmp(argv[1], "to") == 0 | 147 | ws = workspace_create(NULL, ws_name); |
117 | && strcasecmp(argv[2], "output") == 0) { | 148 | } |
118 | if (current->type == C_WORKSPACE) { | 149 | free(ws_name); |
119 | // TODO: Wrap children in a container and move that | ||
120 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | ||
121 | } else if (current->type != C_CONTAINER | ||
122 | && current->type != C_VIEW) { | ||
123 | return cmd_results_new(CMD_FAILURE, "move", | ||
124 | "Can only move containers and views."); | ||
125 | } | 150 | } |
151 | destination = seat_get_focus_inactive(config->handler_context.seat, ws); | ||
152 | } else if (strcasecmp(argv[1], "output") == 0) { | ||
126 | struct sway_container *source = container_parent(current, C_OUTPUT); | 153 | struct sway_container *source = container_parent(current, C_OUTPUT); |
127 | struct sway_container *destination = output_in_direction(argv[3], | 154 | struct sway_container *dest_output = output_in_direction(argv[2], |
128 | source->sway_output->wlr_output, current->x, current->y); | 155 | source->sway_output->wlr_output, current->x, current->y); |
129 | if (!destination) { | 156 | if (!dest_output) { |
130 | return cmd_results_new(CMD_FAILURE, "move workspace", | 157 | return cmd_results_new(CMD_FAILURE, "move workspace", |
131 | "Can't find output with name/direction '%s'", argv[3]); | 158 | "Can't find output with name/direction '%s'", argv[2]); |
132 | } | 159 | } |
133 | struct sway_container *focus = seat_get_focus_inactive( | 160 | destination = seat_get_focus_inactive( |
134 | config->handler_context.seat, destination); | 161 | config->handler_context.seat, dest_output); |
135 | if (!focus) { | 162 | if (!destination) { |
136 | // We've never been to this output before | 163 | // We've never been to this output before |
137 | focus = destination->children->items[0]; | 164 | destination = dest_output->children->items[0]; |
138 | } | 165 | } |
139 | struct sway_container *old_parent = current->parent; | 166 | } else if (strcasecmp(argv[1], "mark") == 0) { |
140 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | 167 | struct sway_view *dest_view = view_find_mark(argv[2]); |
141 | container_move_to(current, focus); | 168 | if (dest_view == NULL) { |
142 | seat_set_focus_warp(config->handler_context.seat, old_parent, true, false); | 169 | return cmd_results_new(CMD_FAILURE, "move", |
143 | container_reap_empty(old_parent); | 170 | "Mark '%s' not found", argv[2]); |
144 | container_reap_empty(focus->parent); | 171 | } |
145 | 172 | destination = dest_view->swayc; | |
146 | // TODO: Ideally we would arrange the surviving parent after reaping, | 173 | } else { |
147 | // but container_reap_empty does not return it, so we arrange the | 174 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
148 | // workspace instead. | ||
149 | arrange_windows(old_ws); | ||
150 | arrange_windows(focus->parent); | ||
151 | |||
152 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
153 | } | 175 | } |
154 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 176 | |
177 | // move container, arrange windows and return focus | ||
178 | container_move_to(current, destination); | ||
179 | struct sway_container *focus = | ||
180 | seat_get_focus_inactive(config->handler_context.seat, old_parent); | ||
181 | seat_set_focus_warp(config->handler_context.seat, focus, true, false); | ||
182 | container_reap_empty(old_parent); | ||
183 | container_reap_empty(destination->parent); | ||
184 | |||
185 | // TODO: Ideally we would arrange the surviving parent after reaping, | ||
186 | // but container_reap_empty does not return it, so we arrange the | ||
187 | // workspace instead. | ||
188 | arrange_windows(old_ws); | ||
189 | arrange_windows(destination->parent); | ||
190 | |||
191 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
155 | } | 192 | } |
156 | 193 | ||
157 | static void workspace_move_to_output(struct sway_container *workspace, | 194 | static void workspace_move_to_output(struct sway_container *workspace, |
@@ -197,20 +234,29 @@ static void workspace_move_to_output(struct sway_container *workspace, | |||
197 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, | 234 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, |
198 | int argc, char **argv) { | 235 | int argc, char **argv) { |
199 | struct cmd_results *error = NULL; | 236 | struct cmd_results *error = NULL; |
200 | if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { | 237 | if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { |
201 | return error; | 238 | return error; |
202 | } else if (strcasecmp(argv[1], "to") != 0 | 239 | } |
203 | || strcasecmp(argv[2], "output") != 0) { | 240 | |
241 | while (strcasecmp(argv[1], "to") == 0) { | ||
242 | if (--argc < 3) { | ||
243 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
244 | } | ||
245 | ++argv; | ||
246 | } | ||
247 | |||
248 | if (strcasecmp(argv[1], "output") != 0) { | ||
204 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 249 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
205 | } | 250 | } |
251 | |||
206 | struct sway_container *source = container_parent(current, C_OUTPUT); | 252 | struct sway_container *source = container_parent(current, C_OUTPUT); |
207 | int center_x = current->width / 2 + current->x, | 253 | int center_x = current->width / 2 + current->x, |
208 | center_y = current->height / 2 + current->y; | 254 | center_y = current->height / 2 + current->y; |
209 | struct sway_container *destination = output_in_direction(argv[3], | 255 | struct sway_container *destination = output_in_direction(argv[2], |
210 | source->sway_output->wlr_output, center_x, center_y); | 256 | source->sway_output->wlr_output, center_x, center_y); |
211 | if (!destination) { | 257 | if (!destination) { |
212 | return cmd_results_new(CMD_FAILURE, "move workspace", | 258 | return cmd_results_new(CMD_FAILURE, "move workspace", |
213 | "Can't find output with name/direction '%s'", argv[3]); | 259 | "Can't find output with name/direction '%s'", argv[2]); |
214 | } | 260 | } |
215 | if (current->type != C_WORKSPACE) { | 261 | if (current->type != C_WORKSPACE) { |
216 | current = container_parent(current, C_WORKSPACE); | 262 | current = container_parent(current, C_WORKSPACE); |
@@ -284,9 +330,9 @@ static struct cmd_results *move_in_direction(struct sway_container *container, | |||
284 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 330 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
285 | } | 331 | } |
286 | 332 | ||
287 | static const char* expected_position_syntax = | 333 | static const char *expected_position_syntax = |
288 | "Expected 'move [absolute] position <x> <y>' or " | 334 | "Expected 'move [absolute] position <x> [px] <y> [px]' or " |
289 | "'move [absolute] position mouse'"; | 335 | "'move [absolute] position center|mouse'"; |
290 | 336 | ||
291 | static struct cmd_results *move_to_position(struct sway_container *container, | 337 | static struct cmd_results *move_to_position(struct sway_container *container, |
292 | int argc, char **argv) { | 338 | int argc, char **argv) { |
@@ -321,10 +367,18 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
321 | double ly = seat->cursor->cursor->y - container->height / 2; | 367 | double ly = seat->cursor->cursor->y - container->height / 2; |
322 | container_floating_move_to(container, lx, ly); | 368 | container_floating_move_to(container, lx, ly); |
323 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 369 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
370 | } else if (strcmp(argv[0], "center") == 0) { | ||
371 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | ||
372 | double lx = ws->x + (ws->width - container->width) / 2; | ||
373 | double ly = ws->y + (ws->height - container->height) / 2; | ||
374 | container_floating_move_to(container, lx, ly); | ||
375 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
324 | } | 376 | } |
325 | if (argc != 2) { | 377 | |
378 | if (argc < 2) { | ||
326 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | 379 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); |
327 | } | 380 | } |
381 | |||
328 | double lx, ly; | 382 | double lx, ly; |
329 | char *inv; | 383 | char *inv; |
330 | lx = (double)strtol(argv[0], &inv, 10); | 384 | lx = (double)strtol(argv[0], &inv, 10); |
@@ -332,11 +386,22 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
332 | return cmd_results_new(CMD_FAILURE, "move", | 386 | return cmd_results_new(CMD_FAILURE, "move", |
333 | "Invalid position specified"); | 387 | "Invalid position specified"); |
334 | } | 388 | } |
389 | if (strcmp(argv[1], "px") == 0) { | ||
390 | --argc; | ||
391 | ++argv; | ||
392 | } | ||
393 | |||
394 | if (argc > 3) { | ||
395 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | ||
396 | } | ||
397 | |||
335 | ly = (double)strtol(argv[1], &inv, 10); | 398 | ly = (double)strtol(argv[1], &inv, 10); |
336 | if (*inv != '\0' && strcasecmp(inv, "px") != 0) { | 399 | if ((*inv != '\0' && strcasecmp(inv, "px") != 0) || |
400 | (argc == 3 && strcmp(argv[2], "px") != 0)) { | ||
337 | return cmd_results_new(CMD_FAILURE, "move", | 401 | return cmd_results_new(CMD_FAILURE, "move", |
338 | "Invalid position specified"); | 402 | "Invalid position specified"); |
339 | } | 403 | } |
404 | |||
340 | container_floating_move_to(container, lx, ly); | 405 | container_floating_move_to(container, lx, ly); |
341 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 406 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
342 | } | 407 | } |
@@ -384,8 +449,11 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
384 | return move_in_direction(current, MOVE_UP, argc, argv); | 449 | return move_in_direction(current, MOVE_UP, argc, argv); |
385 | } else if (strcasecmp(argv[0], "down") == 0) { | 450 | } else if (strcasecmp(argv[0], "down") == 0) { |
386 | return move_in_direction(current, MOVE_DOWN, argc, argv); | 451 | return move_in_direction(current, MOVE_DOWN, argc, argv); |
387 | } else if (strcasecmp(argv[0], "container") == 0 | 452 | } else if ((strcasecmp(argv[0], "container") == 0 |
388 | || strcasecmp(argv[0], "window") == 0) { | 453 | || strcasecmp(argv[0], "window") == 0) || |
454 | (strcasecmp(argv[0], "--no-auto-back-and-forth") && | ||
455 | (strcasecmp(argv[0], "container") == 0 | ||
456 | || strcasecmp(argv[0], "window") == 0))) { | ||
389 | return cmd_move_container(current, argc, argv); | 457 | return cmd_move_container(current, argc, argv); |
390 | } else if (strcasecmp(argv[0], "workspace") == 0) { | 458 | } else if (strcasecmp(argv[0], "workspace") == 0) { |
391 | return cmd_move_workspace(current, argc, argv); | 459 | 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/decoration.c b/sway/decoration.c new file mode 100644 index 00000000..0e3e67ac --- /dev/null +++ b/sway/decoration.c | |||
@@ -0,0 +1,71 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include "sway/decoration.h" | ||
3 | #include "sway/server.h" | ||
4 | #include "sway/tree/view.h" | ||
5 | #include "log.h" | ||
6 | |||
7 | static void server_decoration_handle_destroy(struct wl_listener *listener, | ||
8 | void *data) { | ||
9 | struct sway_server_decoration *deco = | ||
10 | wl_container_of(listener, deco, destroy); | ||
11 | wl_list_remove(&deco->destroy.link); | ||
12 | wl_list_remove(&deco->mode.link); | ||
13 | wl_list_remove(&deco->link); | ||
14 | free(deco); | ||
15 | } | ||
16 | |||
17 | static void server_decoration_handle_mode(struct wl_listener *listener, | ||
18 | void *data) { | ||
19 | struct sway_server_decoration *deco = | ||
20 | wl_container_of(listener, deco, mode); | ||
21 | struct sway_view *view = | ||
22 | view_from_wlr_surface(deco->wlr_server_decoration->surface); | ||
23 | if (view == NULL || view->surface != deco->wlr_server_decoration->surface) { | ||
24 | return; | ||
25 | } | ||
26 | |||
27 | switch (view->type) { | ||
28 | case SWAY_VIEW_XDG_SHELL_V6:; | ||
29 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | ||
30 | (struct sway_xdg_shell_v6_view *)view; | ||
31 | xdg_shell_v6_view->deco_mode = deco->wlr_server_decoration->mode; | ||
32 | break; | ||
33 | case SWAY_VIEW_XDG_SHELL:; | ||
34 | struct sway_xdg_shell_view *xdg_shell_view = | ||
35 | (struct sway_xdg_shell_view *)view; | ||
36 | xdg_shell_view->deco_mode = deco->wlr_server_decoration->mode; | ||
37 | break; | ||
38 | default: | ||
39 | break; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | void handle_server_decoration(struct wl_listener *listener, void *data) { | ||
44 | struct wlr_server_decoration *wlr_deco = data; | ||
45 | |||
46 | struct sway_server_decoration *deco = calloc(1, sizeof(*deco)); | ||
47 | if (deco == NULL) { | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | deco->wlr_server_decoration = wlr_deco; | ||
52 | |||
53 | wl_signal_add(&wlr_deco->events.destroy, &deco->destroy); | ||
54 | deco->destroy.notify = server_decoration_handle_destroy; | ||
55 | |||
56 | wl_signal_add(&wlr_deco->events.mode, &deco->mode); | ||
57 | deco->mode.notify = server_decoration_handle_mode; | ||
58 | |||
59 | wl_list_insert(&server.decorations, &deco->link); | ||
60 | } | ||
61 | |||
62 | struct sway_server_decoration *decoration_from_surface( | ||
63 | struct wlr_surface *surface) { | ||
64 | struct sway_server_decoration *deco; | ||
65 | wl_list_for_each(deco, &server.decorations, link) { | ||
66 | if (deco->wlr_server_decoration->surface == surface) { | ||
67 | return deco; | ||
68 | } | ||
69 | } | ||
70 | return NULL; | ||
71 | } | ||
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index b364663d..3b73f99c 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <wlr/types/wlr_xdg_shell.h> | 6 | #include <wlr/types/wlr_xdg_shell.h> |
7 | #include <wlr/util/edges.h> | 7 | #include <wlr/util/edges.h> |
8 | #include "log.h" | 8 | #include "log.h" |
9 | #include "sway/decoration.h" | ||
9 | #include "sway/input/input-manager.h" | 10 | #include "sway/input/input-manager.h" |
10 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
11 | #include "sway/server.h" | 12 | #include "sway/server.h" |
@@ -170,6 +171,15 @@ static bool wants_floating(struct sway_view *view) { | |||
170 | || toplevel->parent; | 171 | || toplevel->parent; |
171 | } | 172 | } |
172 | 173 | ||
174 | static bool has_client_side_decorations(struct sway_view *view) { | ||
175 | struct sway_xdg_shell_view *xdg_shell_view = | ||
176 | xdg_shell_view_from_view(view); | ||
177 | if (xdg_shell_view == NULL) { | ||
178 | return true; | ||
179 | } | ||
180 | return xdg_shell_view->deco_mode != WLR_SERVER_DECORATION_MANAGER_MODE_SERVER; | ||
181 | } | ||
182 | |||
173 | static void for_each_surface(struct sway_view *view, | 183 | static void for_each_surface(struct sway_view *view, |
174 | wlr_surface_iterator_func_t iterator, void *user_data) { | 184 | wlr_surface_iterator_func_t iterator, void *user_data) { |
175 | if (xdg_shell_view_from_view(view) == NULL) { | 185 | if (xdg_shell_view_from_view(view) == NULL) { |
@@ -226,6 +236,7 @@ static const struct sway_view_impl view_impl = { | |||
226 | .set_tiled = set_tiled, | 236 | .set_tiled = set_tiled, |
227 | .set_fullscreen = set_fullscreen, | 237 | .set_fullscreen = set_fullscreen, |
228 | .wants_floating = wants_floating, | 238 | .wants_floating = wants_floating, |
239 | .has_client_side_decorations = has_client_side_decorations, | ||
229 | .for_each_surface = for_each_surface, | 240 | .for_each_surface = for_each_surface, |
230 | .for_each_popup = for_each_popup, | 241 | .for_each_popup = for_each_popup, |
231 | .close = _close, | 242 | .close = _close, |
@@ -357,6 +368,14 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
357 | view->natural_height = view->wlr_xdg_surface->surface->current.height; | 368 | view->natural_height = view->wlr_xdg_surface->surface->current.height; |
358 | } | 369 | } |
359 | 370 | ||
371 | struct sway_server_decoration *deco = | ||
372 | decoration_from_surface(xdg_surface->surface); | ||
373 | if (deco != NULL) { | ||
374 | xdg_shell_view->deco_mode = deco->wlr_server_decoration->mode; | ||
375 | } else { | ||
376 | xdg_shell_view->deco_mode = WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; | ||
377 | } | ||
378 | |||
360 | view_map(view, view->wlr_xdg_surface->surface); | 379 | view_map(view, view->wlr_xdg_surface->surface); |
361 | 380 | ||
362 | if (xdg_surface->toplevel->client_pending.fullscreen) { | 381 | if (xdg_surface->toplevel->client_pending.fullscreen) { |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index ffea03ad..a947fb35 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -4,14 +4,15 @@ | |||
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
5 | #include <wayland-server.h> | 5 | #include <wayland-server.h> |
6 | #include <wlr/types/wlr_xdg_shell_v6.h> | 6 | #include <wlr/types/wlr_xdg_shell_v6.h> |
7 | #include "log.h" | ||
8 | #include "sway/decoration.h" | ||
9 | #include "sway/input/input-manager.h" | ||
10 | #include "sway/input/seat.h" | ||
7 | #include "sway/server.h" | 11 | #include "sway/server.h" |
8 | #include "sway/tree/arrange.h" | 12 | #include "sway/tree/arrange.h" |
9 | #include "sway/tree/container.h" | 13 | #include "sway/tree/container.h" |
10 | #include "sway/tree/layout.h" | 14 | #include "sway/tree/layout.h" |
11 | #include "sway/tree/view.h" | 15 | #include "sway/tree/view.h" |
12 | #include "sway/input/seat.h" | ||
13 | #include "sway/input/input-manager.h" | ||
14 | #include "log.h" | ||
15 | 16 | ||
16 | static const struct sway_view_child_impl popup_impl; | 17 | static const struct sway_view_child_impl popup_impl; |
17 | 18 | ||
@@ -166,6 +167,15 @@ static bool wants_floating(struct sway_view *view) { | |||
166 | || toplevel->parent; | 167 | || toplevel->parent; |
167 | } | 168 | } |
168 | 169 | ||
170 | static bool has_client_side_decorations(struct sway_view *view) { | ||
171 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | ||
172 | xdg_shell_v6_view_from_view(view); | ||
173 | if (xdg_shell_v6_view == NULL) { | ||
174 | return true; | ||
175 | } | ||
176 | return xdg_shell_v6_view->deco_mode != WLR_SERVER_DECORATION_MANAGER_MODE_SERVER; | ||
177 | } | ||
178 | |||
169 | static void for_each_surface(struct sway_view *view, | 179 | static void for_each_surface(struct sway_view *view, |
170 | wlr_surface_iterator_func_t iterator, void *user_data) { | 180 | wlr_surface_iterator_func_t iterator, void *user_data) { |
171 | if (xdg_shell_v6_view_from_view(view) == NULL) { | 181 | if (xdg_shell_v6_view_from_view(view) == NULL) { |
@@ -223,6 +233,7 @@ static const struct sway_view_impl view_impl = { | |||
223 | .set_tiled = set_tiled, | 233 | .set_tiled = set_tiled, |
224 | .set_fullscreen = set_fullscreen, | 234 | .set_fullscreen = set_fullscreen, |
225 | .wants_floating = wants_floating, | 235 | .wants_floating = wants_floating, |
236 | .has_client_side_decorations = has_client_side_decorations, | ||
226 | .for_each_surface = for_each_surface, | 237 | .for_each_surface = for_each_surface, |
227 | .for_each_popup = for_each_popup, | 238 | .for_each_popup = for_each_popup, |
228 | .close = _close, | 239 | .close = _close, |
@@ -353,6 +364,14 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
353 | view->natural_height = view->wlr_xdg_surface_v6->surface->current.height; | 364 | view->natural_height = view->wlr_xdg_surface_v6->surface->current.height; |
354 | } | 365 | } |
355 | 366 | ||
367 | struct sway_server_decoration *deco = | ||
368 | decoration_from_surface(xdg_surface->surface); | ||
369 | if (deco != NULL) { | ||
370 | xdg_shell_v6_view->deco_mode = deco->wlr_server_decoration->mode; | ||
371 | } else { | ||
372 | xdg_shell_v6_view->deco_mode = WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; | ||
373 | } | ||
374 | |||
356 | view_map(view, view->wlr_xdg_surface_v6->surface); | 375 | view_map(view, view->wlr_xdg_surface_v6->surface); |
357 | 376 | ||
358 | if (xdg_surface->toplevel->client_pending.fullscreen) { | 377 | if (xdg_surface->toplevel->client_pending.fullscreen) { |
diff --git a/sway/meson.build b/sway/meson.build index c18fb6e2..2a457270 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -1,13 +1,14 @@ | |||
1 | sway_sources = files( | 1 | sway_sources = files( |
2 | 'main.c', | ||
3 | 'server.c', | ||
4 | 'commands.c', | 2 | 'commands.c', |
5 | 'config.c', | 3 | 'config.c', |
6 | 'criteria.c', | 4 | 'criteria.c', |
7 | 'debug-tree.c', | 5 | 'debug-tree.c', |
6 | 'decoration.c', | ||
8 | 'ipc-json.c', | 7 | 'ipc-json.c', |
9 | 'ipc-server.c', | 8 | 'ipc-server.c', |
9 | 'main.c', | ||
10 | 'security.c', | 10 | 'security.c', |
11 | 'server.c', | ||
11 | 'swaynag.c', | 12 | 'swaynag.c', |
12 | 13 | ||
13 | 'desktop/desktop.c', | 14 | 'desktop/desktop.c', |
diff --git a/sway/server.c b/sway/server.c index e8755360..e8dc63be 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <wlr/types/wlr_xcursor_manager.h> | 19 | #include <wlr/types/wlr_xcursor_manager.h> |
20 | #include <wlr/types/wlr_xdg_output.h> | 20 | #include <wlr/types/wlr_xdg_output.h> |
21 | #include <wlr/util/log.h> | 21 | #include <wlr/util/log.h> |
22 | // TODO WLR: make Xwayland optional | ||
23 | #include "list.h" | 22 | #include "list.h" |
24 | #include "sway/config.h" | 23 | #include "sway/config.h" |
25 | #include "sway/desktop/idle_inhibit_v1.h" | 24 | #include "sway/desktop/idle_inhibit_v1.h" |
@@ -85,7 +84,6 @@ bool server_init(struct sway_server *server) { | |||
85 | &server->xdg_shell_surface); | 84 | &server->xdg_shell_surface); |
86 | server->xdg_shell_surface.notify = handle_xdg_shell_surface; | 85 | server->xdg_shell_surface.notify = handle_xdg_shell_surface; |
87 | 86 | ||
88 | // TODO make xwayland optional | ||
89 | #ifdef HAVE_XWAYLAND | 87 | #ifdef HAVE_XWAYLAND |
90 | server->xwayland.wlr_xwayland = | 88 | server->xwayland.wlr_xwayland = |
91 | wlr_xwayland_create(server->wl_display, server->compositor, true); | 89 | wlr_xwayland_create(server->wl_display, server->compositor, true); |
@@ -109,11 +107,15 @@ bool server_init(struct sway_server *server) { | |||
109 | } | 107 | } |
110 | #endif | 108 | #endif |
111 | 109 | ||
112 | // TODO: Integration with sway borders | 110 | server->server_decoration_manager = |
113 | struct wlr_server_decoration_manager *deco_manager = | ||
114 | wlr_server_decoration_manager_create(server->wl_display); | 111 | wlr_server_decoration_manager_create(server->wl_display); |
115 | wlr_server_decoration_manager_set_default_mode( | 112 | wlr_server_decoration_manager_set_default_mode( |
116 | deco_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); | 113 | server->server_decoration_manager, |
114 | WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); | ||
115 | wl_signal_add(&server->server_decoration_manager->events.new_decoration, | ||
116 | &server->server_decoration); | ||
117 | server->server_decoration.notify = handle_server_decoration; | ||
118 | wl_list_init(&server->decorations); | ||
117 | 119 | ||
118 | wlr_linux_dmabuf_v1_create(server->wl_display, renderer); | 120 | wlr_linux_dmabuf_v1_create(server->wl_display, renderer); |
119 | wlr_export_dmabuf_manager_v1_create(server->wl_display); | 121 | wlr_export_dmabuf_manager_v1_create(server->wl_display); |
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 9485e675..20815654 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -843,7 +843,7 @@ struct sway_container *container_split(struct sway_container *child, | |||
843 | } | 843 | } |
844 | if (child->type == C_WORKSPACE && child->children->length == 0) { | 844 | if (child->type == C_WORKSPACE && child->children->length == 0) { |
845 | // Special case: this just behaves like splitt | 845 | // Special case: this just behaves like splitt |
846 | child->prev_layout = child->layout; | 846 | child->prev_split_layout = child->layout; |
847 | child->layout = layout; | 847 | child->layout = layout; |
848 | return child; | 848 | return child; |
849 | } | 849 | } |
@@ -854,7 +854,7 @@ struct sway_container *container_split(struct sway_container *child, | |||
854 | 854 | ||
855 | remove_gaps(child); | 855 | remove_gaps(child); |
856 | 856 | ||
857 | cont->prev_layout = L_NONE; | 857 | cont->prev_split_layout = L_NONE; |
858 | cont->width = child->width; | 858 | cont->width = child->width; |
859 | cont->height = child->height; | 859 | cont->height = child->height; |
860 | cont->x = child->x; | 860 | 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); |