summaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar Calvin Lee <cyrus296@gmail.com>2017-04-02 14:38:33 -0600
committerLibravatar Calvin Lee <cyrus296@gmail.com>2017-04-03 11:48:37 -0600
commit2445d279604d7be38c00db60ffde4279a3c75459 (patch)
tree030844d9fb13be7814dd760a6ffedbec8f5264cd /sway
parentUpdate man page (diff)
downloadsway-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
Diffstat (limited to 'sway')
-rw-r--r--sway/border.c23
-rw-r--r--sway/commands.c3
-rw-r--r--sway/commands/mark.c74
-rw-r--r--sway/commands/show_marks.c13
-rw-r--r--sway/commands/unmark.c31
-rw-r--r--sway/config.c1
-rw-r--r--sway/container.c4
-rw-r--r--sway/criteria.c11
-rw-r--r--sway/sway.5.txt20
9 files changed, 180 insertions, 0 deletions
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
8struct 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
5struct 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
7struct 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
13enum criteria_type { // *must* keep in sync with criteria_strings[] 13enum 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
26static const char * const criteria_strings[] = { 27static 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
248int 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).
247static bool criteria_test(swayc_t *cont, list_t *tokens) { 253static 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