diff options
author | Calvin Lee <cyrus296@gmail.com> | 2017-04-02 14:38:33 -0600 |
---|---|---|
committer | Calvin Lee <cyrus296@gmail.com> | 2017-04-03 11:48:37 -0600 |
commit | 2445d279604d7be38c00db60ffde4279a3c75459 (patch) | |
tree | 030844d9fb13be7814dd760a6ffedbec8f5264cd | |
parent | Update man page (diff) | |
download | sway-2445d279604d7be38c00db60ffde4279a3c75459.tar.gz sway-2445d279604d7be38c00db60ffde4279a3c75459.tar.zst sway-2445d279604d7be38c00db60ffde4279a3c75459.zip |
Impliment i3-style marks
This commit adds three commands to sway: `show_marks`, `mark` and
`unmark`. Marks are displayed right-aligned in the window border as i3
does. Marks may be found using criteria.
Fixes #1007
-rw-r--r-- | include/sway/commands.h | 3 | ||||
-rw-r--r-- | include/sway/config.h | 1 | ||||
-rw-r--r-- | include/sway/container.h | 5 | ||||
-rw-r--r-- | sway/border.c | 23 | ||||
-rw-r--r-- | sway/commands.c | 3 | ||||
-rw-r--r-- | sway/commands/mark.c | 74 | ||||
-rw-r--r-- | sway/commands/show_marks.c | 13 | ||||
-rw-r--r-- | sway/commands/unmark.c | 31 | ||||
-rw-r--r-- | sway/config.c | 1 | ||||
-rw-r--r-- | sway/container.c | 4 | ||||
-rw-r--r-- | sway/criteria.c | 11 | ||||
-rw-r--r-- | sway/sway.5.txt | 20 |
12 files changed, 189 insertions, 0 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h index 511bee4d..35a2f92a 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -126,6 +126,7 @@ sway_cmd cmd_ipc; | |||
126 | sway_cmd cmd_kill; | 126 | sway_cmd cmd_kill; |
127 | sway_cmd cmd_layout; | 127 | sway_cmd cmd_layout; |
128 | sway_cmd cmd_log_colors; | 128 | sway_cmd cmd_log_colors; |
129 | sway_cmd cmd_mark; | ||
129 | sway_cmd cmd_mode; | 130 | sway_cmd cmd_mode; |
130 | sway_cmd cmd_mouse_warping; | 131 | sway_cmd cmd_mouse_warping; |
131 | sway_cmd cmd_move; | 132 | sway_cmd cmd_move; |
@@ -140,12 +141,14 @@ sway_cmd cmd_resize; | |||
140 | sway_cmd cmd_scratchpad; | 141 | sway_cmd cmd_scratchpad; |
141 | sway_cmd cmd_seamless_mouse; | 142 | sway_cmd cmd_seamless_mouse; |
142 | sway_cmd cmd_set; | 143 | sway_cmd cmd_set; |
144 | sway_cmd cmd_show_marks; | ||
143 | sway_cmd cmd_smart_gaps; | 145 | sway_cmd cmd_smart_gaps; |
144 | sway_cmd cmd_split; | 146 | sway_cmd cmd_split; |
145 | sway_cmd cmd_splith; | 147 | sway_cmd cmd_splith; |
146 | sway_cmd cmd_splitt; | 148 | sway_cmd cmd_splitt; |
147 | sway_cmd cmd_splitv; | 149 | sway_cmd cmd_splitv; |
148 | sway_cmd cmd_sticky; | 150 | sway_cmd cmd_sticky; |
151 | sway_cmd cmd_unmark; | ||
149 | sway_cmd cmd_workspace; | 152 | sway_cmd cmd_workspace; |
150 | sway_cmd cmd_ws_auto_back_and_forth; | 153 | sway_cmd cmd_ws_auto_back_and_forth; |
151 | sway_cmd cmd_workspace_layout; | 154 | sway_cmd cmd_workspace_layout; |
diff --git a/include/sway/config.h b/include/sway/config.h index d77fbd51..2de90434 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -275,6 +275,7 @@ struct sway_config { | |||
275 | bool reading; | 275 | bool reading; |
276 | bool auto_back_and_forth; | 276 | bool auto_back_and_forth; |
277 | bool seamless_mouse; | 277 | bool seamless_mouse; |
278 | bool show_marks; | ||
278 | 279 | ||
279 | bool edge_gaps; | 280 | bool edge_gaps; |
280 | bool smart_gaps; | 281 | bool smart_gaps; |
diff --git a/include/sway/container.h b/include/sway/container.h index 46925589..37192ce3 100644 --- a/include/sway/container.h +++ b/include/sway/container.h | |||
@@ -165,6 +165,11 @@ struct sway_container { | |||
165 | * Number of slave groups (e.g. columns) in auto layouts. | 165 | * Number of slave groups (e.g. columns) in auto layouts. |
166 | */ | 166 | */ |
167 | size_t nb_slave_groups; | 167 | size_t nb_slave_groups; |
168 | |||
169 | /** | ||
170 | * Marks applied to the container, list_t of char*. | ||
171 | */ | ||
172 | list_t *marks; | ||
168 | }; | 173 | }; |
169 | 174 | ||
170 | enum visibility_mask { | 175 | enum visibility_mask { |
diff --git a/sway/border.c b/sway/border.c index d79029a9..10ad92c2 100644 --- a/sway/border.c +++ b/sway/border.c | |||
@@ -1,8 +1,11 @@ | |||
1 | #define _XOPEN_SOURCE 500 | ||
1 | #include <wlc/wlc-render.h> | 2 | #include <wlc/wlc-render.h> |
2 | #include <cairo/cairo.h> | 3 | #include <cairo/cairo.h> |
3 | #include <pango/pangocairo.h> | 4 | #include <pango/pangocairo.h> |
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <string.h> | ||
8 | #include <strings.h> | ||
6 | #include <arpa/inet.h> | 9 | #include <arpa/inet.h> |
7 | #include "sway/border.h" | 10 | #include "sway/border.h" |
8 | #include "sway/container.h" | 11 | #include "sway/container.h" |
@@ -190,6 +193,26 @@ static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, | |||
190 | cairo_set_source_u32(cr, colors->text); | 193 | cairo_set_source_u32(cr, colors->text); |
191 | pango_printf(cr, config->font, 1, false, "%s", view->name); | 194 | pango_printf(cr, config->font, 1, false, "%s", view->name); |
192 | } | 195 | } |
196 | // Marks | ||
197 | if (config->show_marks && view->marks) { | ||
198 | int total_len = 0; | ||
199 | |||
200 | for(int i = view->marks->length - 1; i >= 0; --i) { | ||
201 | char *mark = (char *)view->marks->items[i]; | ||
202 | if (*mark != '_') { | ||
203 | int width, height; | ||
204 | get_text_size(cr, config->font, &width, &height, 1, false, "[%s]", mark); | ||
205 | total_len += width; | ||
206 | if ((int)tb->size.w + x - (total_len + 2) < x + 2) { | ||
207 | break; | ||
208 | } else { | ||
209 | cairo_move_to(cr, (int)tb->size.w + x - (total_len + 2), y + 2); | ||
210 | cairo_set_source_u32(cr, colors->text); | ||
211 | pango_printf(cr, config->font, 1, false, "[%s]", mark); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
193 | 216 | ||
194 | // titlebars has a border all around for tabbed layouts | 217 | // titlebars has a border all around for tabbed layouts |
195 | if (view->parent->layout == L_TABBED) { | 218 | if (view->parent->layout == L_TABBED) { |
diff --git a/sway/commands.c b/sway/commands.c index c330ebee..971ff505 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -190,6 +190,7 @@ static struct cmd_handler handlers[] = { | |||
190 | { "kill", cmd_kill }, | 190 | { "kill", cmd_kill }, |
191 | { "layout", cmd_layout }, | 191 | { "layout", cmd_layout }, |
192 | { "log_colors", cmd_log_colors }, | 192 | { "log_colors", cmd_log_colors }, |
193 | { "mark", cmd_mark }, | ||
193 | { "mode", cmd_mode }, | 194 | { "mode", cmd_mode }, |
194 | { "mouse_warping", cmd_mouse_warping }, | 195 | { "mouse_warping", cmd_mouse_warping }, |
195 | { "move", cmd_move }, | 196 | { "move", cmd_move }, |
@@ -203,12 +204,14 @@ static struct cmd_handler handlers[] = { | |||
203 | { "scratchpad", cmd_scratchpad }, | 204 | { "scratchpad", cmd_scratchpad }, |
204 | { "seamless_mouse", cmd_seamless_mouse }, | 205 | { "seamless_mouse", cmd_seamless_mouse }, |
205 | { "set", cmd_set }, | 206 | { "set", cmd_set }, |
207 | { "show_marks", cmd_show_marks }, | ||
206 | { "smart_gaps", cmd_smart_gaps }, | 208 | { "smart_gaps", cmd_smart_gaps }, |
207 | { "split", cmd_split }, | 209 | { "split", cmd_split }, |
208 | { "splith", cmd_splith }, | 210 | { "splith", cmd_splith }, |
209 | { "splitt", cmd_splitt }, | 211 | { "splitt", cmd_splitt }, |
210 | { "splitv", cmd_splitv }, | 212 | { "splitv", cmd_splitv }, |
211 | { "sticky", cmd_sticky }, | 213 | { "sticky", cmd_sticky }, |
214 | { "unmark", cmd_unmark }, | ||
212 | { "workspace", cmd_workspace }, | 215 | { "workspace", cmd_workspace }, |
213 | { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, | 216 | { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, |
214 | { "workspace_layout", cmd_workspace_layout }, | 217 | { "workspace_layout", cmd_workspace_layout }, |
diff --git a/sway/commands/mark.c b/sway/commands/mark.c new file mode 100644 index 00000000..68a84af7 --- /dev/null +++ b/sway/commands/mark.c | |||
@@ -0,0 +1,74 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include <stdbool.h> | ||
4 | #include "sway/commands.h" | ||
5 | #include "list.h" | ||
6 | #include "stringop.h" | ||
7 | |||
8 | struct cmd_results *cmd_mark(int argc, char **argv) { | ||
9 | struct cmd_results *error = NULL; | ||
10 | if (config->reading) return cmd_results_new(CMD_FAILURE, "mark", "Can't be used in config file."); | ||
11 | if ((error = checkarg(argc, "floating", EXPECTED_AT_LEAST, 1))) { | ||
12 | return error; | ||
13 | } | ||
14 | |||
15 | swayc_t *view = get_focused_container(&root_container); | ||
16 | bool add = false; | ||
17 | bool toggle = false; | ||
18 | |||
19 | if (strcmp(argv[0], "--add") == 0) { | ||
20 | --argc; ++argv; | ||
21 | add = true; | ||
22 | } else if (strcmp(argv[0], "--replace") == 0) { | ||
23 | --argc; ++argv; | ||
24 | } | ||
25 | |||
26 | if (argc && strcmp(argv[0], "--toggle") == 0) { | ||
27 | --argc; ++argv; | ||
28 | toggle = true; | ||
29 | } | ||
30 | |||
31 | if (argc) { | ||
32 | char *mark = join_args(argv, argc); | ||
33 | if (view->marks) { | ||
34 | if (add) { | ||
35 | int index; | ||
36 | if ((index = list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1) { | ||
37 | if (toggle) { | ||
38 | free(view->marks->items[index]); | ||
39 | list_del(view->marks, index); | ||
40 | |||
41 | if (0 == view->marks->length) { | ||
42 | list_free(view->marks); | ||
43 | view->marks = NULL; | ||
44 | } | ||
45 | } | ||
46 | free(mark); | ||
47 | } else { | ||
48 | list_add(view->marks, mark); | ||
49 | } | ||
50 | } else { | ||
51 | if (toggle && list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark) != -1) { | ||
52 | // Delete the list | ||
53 | list_foreach(view->marks, free); | ||
54 | list_free(view->marks); | ||
55 | view->marks = NULL; | ||
56 | } else { | ||
57 | // Delete and replace with a new list | ||
58 | list_foreach(view->marks, free); | ||
59 | list_free(view->marks); | ||
60 | |||
61 | view->marks = create_list(); | ||
62 | list_add(view->marks, mark); | ||
63 | } | ||
64 | } | ||
65 | } else { | ||
66 | view->marks = create_list(); | ||
67 | list_add(view->marks, mark); | ||
68 | } | ||
69 | } else { | ||
70 | return cmd_results_new(CMD_FAILURE, "mark", | ||
71 | "Expected 'mark [--add|--replace] [--toggle] <mark>'"); | ||
72 | } | ||
73 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
74 | } | ||
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c new file mode 100644 index 00000000..ed56d9e5 --- /dev/null +++ b/sway/commands/show_marks.c | |||
@@ -0,0 +1,13 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/commands.h" | ||
4 | |||
5 | struct cmd_results *cmd_show_marks(int argc, char **argv) { | ||
6 | struct cmd_results *error = NULL; | ||
7 | if ((error = checkarg(argc, "show_marks", EXPECTED_EQUAL_TO, 1))) { | ||
8 | return error; | ||
9 | } | ||
10 | |||
11 | config->show_marks = !strcasecmp(argv[0], "on"); | ||
12 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
13 | } | ||
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c new file mode 100644 index 00000000..34a2ae44 --- /dev/null +++ b/sway/commands/unmark.c | |||
@@ -0,0 +1,31 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/commands.h" | ||
4 | #include "list.h" | ||
5 | #include "stringop.h" | ||
6 | |||
7 | struct cmd_results *cmd_unmark(int argc, char **argv) { | ||
8 | swayc_t *view = get_focused_container(&root_container); | ||
9 | |||
10 | if (view->marks) { | ||
11 | if (argc) { | ||
12 | char *mark = join_args(argv, argc); | ||
13 | int index; | ||
14 | if ((index = list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1) { | ||
15 | free(view->marks->items[index]); | ||
16 | list_del(view->marks, index); | ||
17 | |||
18 | if (view->marks->length == 0) { | ||
19 | list_free(view->marks); | ||
20 | view->marks = NULL; | ||
21 | } | ||
22 | } | ||
23 | free(mark); | ||
24 | } else { | ||
25 | list_foreach(view->marks, free); | ||
26 | list_free(view->marks); | ||
27 | view->marks = NULL; | ||
28 | } | ||
29 | } | ||
30 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
31 | } | ||
diff --git a/sway/config.c b/sway/config.c index 46faf643..c8432a2a 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -329,6 +329,7 @@ static void config_defaults(struct sway_config *config) { | |||
329 | config->auto_back_and_forth = false; | 329 | config->auto_back_and_forth = false; |
330 | config->seamless_mouse = true; | 330 | config->seamless_mouse = true; |
331 | config->reading = false; | 331 | config->reading = false; |
332 | config->show_marks = true; | ||
332 | 333 | ||
333 | config->edge_gaps = true; | 334 | config->edge_gaps = true; |
334 | config->smart_gaps = false; | 335 | config->smart_gaps = false; |
diff --git a/sway/container.c b/sway/container.c index 707aa4d8..08aa77a8 100644 --- a/sway/container.c +++ b/sway/container.c | |||
@@ -61,6 +61,10 @@ static void free_swayc(swayc_t *cont) { | |||
61 | } | 61 | } |
62 | list_free(cont->floating); | 62 | list_free(cont->floating); |
63 | } | 63 | } |
64 | if (cont->marks) { | ||
65 | list_foreach(cont->marks, free); | ||
66 | list_free(cont->marks); | ||
67 | } | ||
64 | if (cont->parent) { | 68 | if (cont->parent) { |
65 | remove_child(cont); | 69 | remove_child(cont); |
66 | } | 70 | } |
diff --git a/sway/criteria.c b/sway/criteria.c index bc0523ce..3ffc48f0 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | enum criteria_type { // *must* keep in sync with criteria_strings[] | 13 | enum criteria_type { // *must* keep in sync with criteria_strings[] |
14 | CRIT_CLASS, | 14 | CRIT_CLASS, |
15 | CRIT_CON_MARK, | ||
15 | CRIT_ID, | 16 | CRIT_ID, |
16 | CRIT_INSTANCE, | 17 | CRIT_INSTANCE, |
17 | CRIT_TITLE, | 18 | CRIT_TITLE, |
@@ -25,6 +26,7 @@ enum criteria_type { // *must* keep in sync with criteria_strings[] | |||
25 | // this *must* match the ordering in criteria_type enum | 26 | // this *must* match the ordering in criteria_type enum |
26 | static const char * const criteria_strings[] = { | 27 | static const char * const criteria_strings[] = { |
27 | "class", | 28 | "class", |
29 | "con_mark", | ||
28 | "id", | 30 | "id", |
29 | "instance", | 31 | "instance", |
30 | "title", | 32 | "title", |
@@ -243,6 +245,10 @@ ect_cleanup: | |||
243 | return error; | 245 | return error; |
244 | } | 246 | } |
245 | 247 | ||
248 | int regex_cmp(const char *item, const regex_t *regex) { | ||
249 | return regexec(regex, item, 0, NULL, 0); | ||
250 | } | ||
251 | |||
246 | // test a single view if it matches list of criteria tokens (all of them). | 252 | // test a single view if it matches list of criteria tokens (all of them). |
247 | static bool criteria_test(swayc_t *cont, list_t *tokens) { | 253 | static bool criteria_test(swayc_t *cont, list_t *tokens) { |
248 | if (cont->type != C_VIEW) { | 254 | if (cont->type != C_VIEW) { |
@@ -264,6 +270,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
264 | matches++; | 270 | matches++; |
265 | } | 271 | } |
266 | break; | 272 | break; |
273 | case CRIT_CON_MARK: | ||
274 | if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { | ||
275 | ++matches; | ||
276 | } | ||
277 | break; | ||
267 | case CRIT_ID: | 278 | case CRIT_ID: |
268 | if (!cont->app_id) { | 279 | if (!cont->app_id) { |
269 | // ignore | 280 | // ignore |
diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 5d143d97..3cccdfd5 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt | |||
@@ -316,6 +316,14 @@ The default colors are: | |||
316 | If smart_gaps are _on_ then gaps will only be enabled if a workspace has more | 316 | If smart_gaps are _on_ then gaps will only be enabled if a workspace has more |
317 | than one child container. | 317 | than one child container. |
318 | 318 | ||
319 | **mark** <--add|--replace> <--toggle> <identifier>:: | ||
320 | Marks are arbitrary labels that can be used to identify certain windows and | ||
321 | then jump to them at a later time. By default, the **mark** command sets | ||
322 | _identifier_ as the only mark on a window. By specifying _--add_, mark will | ||
323 | add _identifier_ to the list of current marks. If _--toggle_ is specified mark | ||
324 | will remove _identifier_ if it is already a label. Marks may be found by using | ||
325 | a criteria. See the **Criteria** section below. | ||
326 | |||
319 | **mode** <mode_name>:: | 327 | **mode** <mode_name>:: |
320 | Switches to the given mode_name. The default mode is simply _default_. To | 328 | Switches to the given mode_name. The default mode is simply _default_. To |
321 | create a new mode in config append _{_ to this command, the following lines | 329 | create a new mode in config append _{_ to this command, the following lines |
@@ -368,6 +376,15 @@ The default colors are: | |||
368 | be configured with perfectly aligned adjacent positions for this option to | 376 | be configured with perfectly aligned adjacent positions for this option to |
369 | have any effect. | 377 | have any effect. |
370 | 378 | ||
379 | **show_marks** <on|off>:: | ||
380 | If **show_marks** is on then marks will be showed in the window decoration. | ||
381 | However, any mark that starts with an underscore will not be drawn even if the | ||
382 | option is on. The default option is _on_. | ||
383 | |||
384 | **unmark** <identifier>:: | ||
385 | **Unmark** will remove _identifier_ from the list of current marks on a window. If | ||
386 | no _identifier_ is specified then **unmark** will remove all marks. | ||
387 | |||
371 | **workspace** [number] <name>:: | 388 | **workspace** [number] <name>:: |
372 | Switches to the specified workspace. The string "number" is optional. The | 389 | Switches to the specified workspace. The string "number" is optional. The |
373 | worspace _name_, if unquoted, may not contain the string "output", as sway | 390 | worspace _name_, if unquoted, may not contain the string "output", as sway |
@@ -416,6 +433,9 @@ Currently supported attributes: | |||
416 | is _focused_ then the window class must be the same as that of the currently | 433 | is _focused_ then the window class must be the same as that of the currently |
417 | focused window. | 434 | focused window. |
418 | 435 | ||
436 | **con_mark**:: | ||
437 | Compare against the window marks. Can be a regular expression. | ||
438 | |||
419 | **id**:: | 439 | **id**:: |
420 | Compare value against the app id. Can be a regular expression. | 440 | Compare value against the app id. Can be a regular expression. |
421 | 441 | ||