diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | CMake/FindLibcap.cmake | 56 | ||||
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | include/sway/commands.h | 6 | ||||
-rw-r--r-- | include/sway/config.h | 1 | ||||
-rw-r--r-- | include/sway/container.h | 5 | ||||
-rw-r--r-- | include/sway/criteria.h | 3 | ||||
-rw-r--r-- | sway/border.c | 23 | ||||
-rw-r--r-- | sway/commands.c | 82 | ||||
-rw-r--r-- | sway/commands/border.c | 2 | ||||
-rw-r--r-- | sway/commands/floating.c | 2 | ||||
-rw-r--r-- | sway/commands/focus.c | 3 | ||||
-rw-r--r-- | sway/commands/fullscreen.c | 2 | ||||
-rw-r--r-- | sway/commands/kill.c | 2 | ||||
-rw-r--r-- | sway/commands/layout.c | 2 | ||||
-rw-r--r-- | sway/commands/mark.c | 87 | ||||
-rw-r--r-- | sway/commands/move.c | 4 | ||||
-rw-r--r-- | sway/commands/resize.c | 12 | ||||
-rw-r--r-- | sway/commands/show_marks.c | 13 | ||||
-rw-r--r-- | sway/commands/split.c | 6 | ||||
-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 | 89 | ||||
-rw-r--r-- | sway/ipc-server.c | 30 | ||||
-rw-r--r-- | sway/main.c | 2 | ||||
-rw-r--r-- | sway/sway.1.txt | 4 | ||||
-rw-r--r-- | sway/sway.5.txt | 34 |
28 files changed, 424 insertions, 84 deletions
diff --git a/.travis.yml b/.travis.yml index a8e292ba..2bb17d40 100644 --- a/.travis.yml +++ b/.travis.yml | |||
@@ -18,6 +18,7 @@ arch: | |||
18 | - cairo | 18 | - cairo |
19 | - gdk-pixbuf2 | 19 | - gdk-pixbuf2 |
20 | - wlc-git | 20 | - wlc-git |
21 | - libcap | ||
21 | script: | 22 | script: |
22 | - "cmake ." | 23 | - "cmake ." |
23 | - "make" | 24 | - "make" |
diff --git a/CMake/FindLibcap.cmake b/CMake/FindLibcap.cmake new file mode 100644 index 00000000..b34e5e37 --- /dev/null +++ b/CMake/FindLibcap.cmake | |||
@@ -0,0 +1,56 @@ | |||
1 | #.rst: | ||
2 | # FindLibcap | ||
3 | # ------- | ||
4 | # | ||
5 | # Find Libcap library | ||
6 | # | ||
7 | # Try to find Libcap library. The following values are defined | ||
8 | # | ||
9 | # :: | ||
10 | # | ||
11 | # Libcap_FOUND - True if Libcap is available | ||
12 | # Libcap_INCLUDE_DIRS - Include directories for Libcap | ||
13 | # Libcap_LIBRARIES - List of libraries for Libcap | ||
14 | # Libcap_DEFINITIONS - List of definitions for Libcap | ||
15 | # | ||
16 | # and also the following more fine grained variables | ||
17 | # | ||
18 | # :: | ||
19 | # | ||
20 | # Libcap_VERSION | ||
21 | # Libcap_VERSION_MAJOR | ||
22 | # Libcap_VERSION_MINOR | ||
23 | # | ||
24 | #============================================================================= | ||
25 | # Copyright (c) 2017 Jerzi Kaminsky | ||
26 | # | ||
27 | # Distributed under the OSI-approved BSD License (the "License"); | ||
28 | # | ||
29 | # This software is distributed WITHOUT ANY WARRANTY; without even the | ||
30 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
31 | # See the License for more information. | ||
32 | #============================================================================= | ||
33 | |||
34 | include(FeatureSummary) | ||
35 | set_package_properties(Libcap PROPERTIES | ||
36 | URL "https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2" | ||
37 | DESCRIPTION "Library for getting and setting POSIX.1e capabilities") | ||
38 | |||
39 | find_package(PkgConfig) | ||
40 | pkg_check_modules(PC_CAP QUIET Libcap) | ||
41 | find_library(Libcap_LIBRARIES NAMES cap HINTS ${PC_CAP_LIBRARY_DIRS}) | ||
42 | find_path(Libcap_INCLUDE_DIRS sys/capability.h HINTS ${PC_CAP_INCLUDE_DIRS}) | ||
43 | |||
44 | set(Libcap_VERSION ${PC_CAP_VERSION}) | ||
45 | string(REPLACE "." ";" VERSION_LIST "${PC_CAP_VERSION}") | ||
46 | |||
47 | LIST(LENGTH VERSION_LIST n) | ||
48 | if (n EQUAL 2) | ||
49 | list(GET VERSION_LIST 0 Libcap_VERSION_MAJOR) | ||
50 | list(GET VERSION_LIST 1 Libcap_VERSION_MINOR) | ||
51 | endif () | ||
52 | |||
53 | include(FindPackageHandleStandardArgs) | ||
54 | find_package_handle_standard_args(Libcap DEFAULT_MSG Libcap_INCLUDE_DIRS Libcap_LIBRARIES) | ||
55 | mark_as_advanced(Libcap_INCLUDE_DIRS Libcap_LIBRARIES Libcap_DEFINITIONS | ||
56 | Libcap_VERSION Libcap_VERSION_MAJOR Libcap_VERSION_MICRO Libcap_VERSION_MINOR) | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index ec2c73a2..017b0994 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -66,6 +66,7 @@ find_package(GdkPixbuf) | |||
66 | find_package(PAM) | 66 | find_package(PAM) |
67 | 67 | ||
68 | find_package(LibInput REQUIRED) | 68 | find_package(LibInput REQUIRED) |
69 | find_package(Libcap REQUIRED) | ||
69 | 70 | ||
70 | if (CMAKE_SYSTEM_NAME STREQUAL FreeBSD) | 71 | if (CMAKE_SYSTEM_NAME STREQUAL FreeBSD) |
71 | find_package(EpollShim REQUIRED) | 72 | find_package(EpollShim REQUIRED) |
diff --git a/include/sway/commands.h b/include/sway/commands.h index 511bee4d..91f2ae01 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -5,6 +5,9 @@ | |||
5 | #include <wlc/wlc.h> | 5 | #include <wlc/wlc.h> |
6 | #include "config.h" | 6 | #include "config.h" |
7 | 7 | ||
8 | // Container that a called command should act upon. Only valid in command functions. | ||
9 | extern swayc_t *current_container; | ||
10 | |||
8 | /** | 11 | /** |
9 | * Indicates the result of a command's execution. | 12 | * Indicates the result of a command's execution. |
10 | */ | 13 | */ |
@@ -126,6 +129,7 @@ sway_cmd cmd_ipc; | |||
126 | sway_cmd cmd_kill; | 129 | sway_cmd cmd_kill; |
127 | sway_cmd cmd_layout; | 130 | sway_cmd cmd_layout; |
128 | sway_cmd cmd_log_colors; | 131 | sway_cmd cmd_log_colors; |
132 | sway_cmd cmd_mark; | ||
129 | sway_cmd cmd_mode; | 133 | sway_cmd cmd_mode; |
130 | sway_cmd cmd_mouse_warping; | 134 | sway_cmd cmd_mouse_warping; |
131 | sway_cmd cmd_move; | 135 | sway_cmd cmd_move; |
@@ -140,12 +144,14 @@ sway_cmd cmd_resize; | |||
140 | sway_cmd cmd_scratchpad; | 144 | sway_cmd cmd_scratchpad; |
141 | sway_cmd cmd_seamless_mouse; | 145 | sway_cmd cmd_seamless_mouse; |
142 | sway_cmd cmd_set; | 146 | sway_cmd cmd_set; |
147 | sway_cmd cmd_show_marks; | ||
143 | sway_cmd cmd_smart_gaps; | 148 | sway_cmd cmd_smart_gaps; |
144 | sway_cmd cmd_split; | 149 | sway_cmd cmd_split; |
145 | sway_cmd cmd_splith; | 150 | sway_cmd cmd_splith; |
146 | sway_cmd cmd_splitt; | 151 | sway_cmd cmd_splitt; |
147 | sway_cmd cmd_splitv; | 152 | sway_cmd cmd_splitv; |
148 | sway_cmd cmd_sticky; | 153 | sway_cmd cmd_sticky; |
154 | sway_cmd cmd_unmark; | ||
149 | sway_cmd cmd_workspace; | 155 | sway_cmd cmd_workspace; |
150 | sway_cmd cmd_ws_auto_back_and_forth; | 156 | sway_cmd cmd_ws_auto_back_and_forth; |
151 | sway_cmd cmd_workspace_layout; | 157 | 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/include/sway/criteria.h b/include/sway/criteria.h index 5c71d172..022c48a8 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h | |||
@@ -33,4 +33,7 @@ char *extract_crit_tokens(list_t *tokens, const char *criteria); | |||
33 | // been set with `for_window` commands and have an associated cmdlist. | 33 | // been set with `for_window` commands and have an associated cmdlist. |
34 | list_t *criteria_for(swayc_t *cont); | 34 | list_t *criteria_for(swayc_t *cont); |
35 | 35 | ||
36 | // Returns a list of all containers that match the given list of tokens. | ||
37 | list_t *container_for(list_t *tokens); | ||
38 | |||
36 | #endif | 39 | #endif |
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..17c7d717 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -43,6 +43,8 @@ struct cmd_handler { | |||
43 | 43 | ||
44 | int sp_index = 0; | 44 | int sp_index = 0; |
45 | 45 | ||
46 | swayc_t *current_container = NULL; | ||
47 | |||
46 | // Returns error object, or NULL if check succeeds. | 48 | // Returns error object, or NULL if check succeeds. |
47 | struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { | 49 | struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { |
48 | struct cmd_results *error = NULL; | 50 | struct cmd_results *error = NULL; |
@@ -190,6 +192,7 @@ static struct cmd_handler handlers[] = { | |||
190 | { "kill", cmd_kill }, | 192 | { "kill", cmd_kill }, |
191 | { "layout", cmd_layout }, | 193 | { "layout", cmd_layout }, |
192 | { "log_colors", cmd_log_colors }, | 194 | { "log_colors", cmd_log_colors }, |
195 | { "mark", cmd_mark }, | ||
193 | { "mode", cmd_mode }, | 196 | { "mode", cmd_mode }, |
194 | { "mouse_warping", cmd_mouse_warping }, | 197 | { "mouse_warping", cmd_mouse_warping }, |
195 | { "move", cmd_move }, | 198 | { "move", cmd_move }, |
@@ -203,12 +206,14 @@ static struct cmd_handler handlers[] = { | |||
203 | { "scratchpad", cmd_scratchpad }, | 206 | { "scratchpad", cmd_scratchpad }, |
204 | { "seamless_mouse", cmd_seamless_mouse }, | 207 | { "seamless_mouse", cmd_seamless_mouse }, |
205 | { "set", cmd_set }, | 208 | { "set", cmd_set }, |
209 | { "show_marks", cmd_show_marks }, | ||
206 | { "smart_gaps", cmd_smart_gaps }, | 210 | { "smart_gaps", cmd_smart_gaps }, |
207 | { "split", cmd_split }, | 211 | { "split", cmd_split }, |
208 | { "splith", cmd_splith }, | 212 | { "splith", cmd_splith }, |
209 | { "splitt", cmd_splitt }, | 213 | { "splitt", cmd_splitt }, |
210 | { "splitv", cmd_splitv }, | 214 | { "splitv", cmd_splitv }, |
211 | { "sticky", cmd_sticky }, | 215 | { "sticky", cmd_sticky }, |
216 | { "unmark", cmd_unmark }, | ||
212 | { "workspace", cmd_workspace }, | 217 | { "workspace", cmd_workspace }, |
213 | { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, | 218 | { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, |
214 | { "workspace_layout", cmd_workspace_layout }, | 219 | { "workspace_layout", cmd_workspace_layout }, |
@@ -368,42 +373,37 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
368 | char *head = exec; | 373 | char *head = exec; |
369 | char *cmdlist; | 374 | char *cmdlist; |
370 | char *cmd; | 375 | char *cmd; |
371 | char *criteria __attribute__((unused)); | 376 | list_t *containers = NULL; |
372 | 377 | ||
373 | head = exec; | 378 | head = exec; |
374 | do { | 379 | do { |
375 | // Extract criteria (valid for this command list only). | 380 | // Extract criteria (valid for this command list only). |
376 | criteria = NULL; | ||
377 | if (*head == '[') { | 381 | if (*head == '[') { |
378 | ++head; | 382 | ++head; |
379 | criteria = argsep(&head, "]"); | 383 | char *criteria_string = argsep(&head, "]"); |
380 | if (head) { | 384 | if (head) { |
381 | ++head; | 385 | ++head; |
382 | // TODO handle criteria | 386 | list_t *tokens = create_list(); |
387 | char *error; | ||
388 | |||
389 | if ((error = extract_crit_tokens(tokens, criteria_string))) { | ||
390 | results = cmd_results_new(CMD_INVALID, criteria_string, | ||
391 | "Can't parse criteria string: %s", error); | ||
392 | free(error); | ||
393 | free(tokens); | ||
394 | goto cleanup; | ||
395 | } | ||
396 | containers = container_for(tokens); | ||
397 | |||
398 | free(tokens); | ||
383 | } else { | 399 | } else { |
384 | if (!results) { | 400 | if (!results) { |
385 | results = cmd_results_new(CMD_INVALID, criteria, "Unmatched ["); | 401 | results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched ["); |
386 | } | 402 | } |
387 | goto cleanup; | 403 | goto cleanup; |
388 | } | 404 | } |
389 | // Skip leading whitespace | 405 | // Skip leading whitespace |
390 | head += strspn(head, whitespace); | 406 | head += strspn(head, whitespace); |
391 | |||
392 | // TODO: it will yield unexpected results to execute commands | ||
393 | // (on any view) that where meant for certain views only. | ||
394 | if (!results) { | ||
395 | int len = strlen(criteria) + strlen(head) + 4; | ||
396 | char *tmp = malloc(len); | ||
397 | if (tmp) { | ||
398 | snprintf(tmp, len, "[%s] %s", criteria, head); | ||
399 | } else { | ||
400 | sway_log(L_DEBUG, "Unable to allocate criteria string for cmd result"); | ||
401 | } | ||
402 | results = cmd_results_new(CMD_INVALID, tmp, | ||
403 | "Can't handle criteria string: Refusing to execute command"); | ||
404 | free(tmp); | ||
405 | } | ||
406 | goto cleanup; | ||
407 | } | 407 | } |
408 | // Split command list | 408 | // Split command list |
409 | cmdlist = argsep(&head, ";"); | 409 | cmdlist = argsep(&head, ";"); |
@@ -447,21 +447,43 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
447 | free_argv(argc, argv); | 447 | free_argv(argc, argv); |
448 | goto cleanup; | 448 | goto cleanup; |
449 | } | 449 | } |
450 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 450 | int i = 0; |
451 | if (res->status != CMD_SUCCESS) { | 451 | do { |
452 | free_argv(argc, argv); | 452 | if (!containers) { |
453 | if (results) { | 453 | current_container = get_focused_container(&root_container); |
454 | free_cmd_results(results); | 454 | } else if (containers->length == 0) { |
455 | break; | ||
456 | } else { | ||
457 | current_container = (swayc_t *)containers->items[i]; | ||
455 | } | 458 | } |
456 | results = res; | 459 | sway_log(L_INFO, "Running on container '%s'", current_container->name); |
457 | goto cleanup; | 460 | |
458 | } | 461 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
462 | if (res->status != CMD_SUCCESS) { | ||
463 | free_argv(argc, argv); | ||
464 | if (results) { | ||
465 | free_cmd_results(results); | ||
466 | } | ||
467 | results = res; | ||
468 | goto cleanup; | ||
469 | } | ||
470 | free_cmd_results(res); | ||
471 | ++i; | ||
472 | } while(containers && i < containers->length); | ||
473 | |||
459 | free_argv(argc, argv); | 474 | free_argv(argc, argv); |
460 | free_cmd_results(res); | ||
461 | } while(cmdlist); | 475 | } while(cmdlist); |
476 | |||
477 | if (containers) { | ||
478 | list_free(containers); | ||
479 | containers = NULL; | ||
480 | } | ||
462 | } while(head); | 481 | } while(head); |
463 | cleanup: | 482 | cleanup: |
464 | free(exec); | 483 | free(exec); |
484 | if (containers) { | ||
485 | free(containers); | ||
486 | } | ||
465 | if (!results) { | 487 | if (!results) { |
466 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); | 488 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); |
467 | } | 489 | } |
diff --git a/sway/commands/border.c b/sway/commands/border.c index 0211e40c..c888622e 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c | |||
@@ -20,7 +20,7 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
20 | "Expected 'border <normal|pixel|none|toggle> [<n>]"); | 20 | "Expected 'border <normal|pixel|none|toggle> [<n>]"); |
21 | } | 21 | } |
22 | 22 | ||
23 | swayc_t *view = get_focused_view(&root_container); | 23 | swayc_t *view = current_container; |
24 | enum swayc_border_types border = view->border_type; | 24 | enum swayc_border_types border = view->border_type; |
25 | int thickness = view->border_thickness; | 25 | int thickness = view->border_thickness; |
26 | 26 | ||
diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 113c8b71..ccfde532 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c | |||
@@ -13,7 +13,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
13 | if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { | 13 | if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { |
14 | return error; | 14 | return error; |
15 | } | 15 | } |
16 | swayc_t *view = get_focused_container(&root_container); | 16 | swayc_t *view = current_container; |
17 | bool wants_floating; | 17 | bool wants_floating; |
18 | if (strcasecmp(argv[0], "enable") == 0) { | 18 | if (strcasecmp(argv[0], "enable") == 0) { |
19 | wants_floating = true; | 19 | wants_floating = true; |
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 12c5d02c..defaba29 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c | |||
@@ -30,6 +30,9 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
30 | } | 30 | } |
31 | } | 31 | } |
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
33 | } else if (argc == 0) { | ||
34 | set_focused_container(current_container); | ||
35 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
33 | } else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) { | 36 | } else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) { |
34 | return error; | 37 | return error; |
35 | } | 38 | } |
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 321d6f59..bfff82f9 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c | |||
@@ -14,7 +14,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
14 | if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0))) { | 14 | if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0))) { |
15 | return error; | 15 | return error; |
16 | } | 16 | } |
17 | swayc_t *container = get_focused_view(&root_container); | 17 | swayc_t *container = current_container; |
18 | if(container->type != C_VIEW){ | 18 | if(container->type != C_VIEW){ |
19 | return cmd_results_new(CMD_INVALID, "fullscreen", "Only views can fullscreen"); | 19 | return cmd_results_new(CMD_INVALID, "fullscreen", "Only views can fullscreen"); |
20 | } | 20 | } |
diff --git a/sway/commands/kill.c b/sway/commands/kill.c index 2e94fb10..742e2b86 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c | |||
@@ -6,7 +6,7 @@ struct cmd_results *cmd_kill(int argc, char **argv) { | |||
6 | if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file."); | 6 | if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file."); |
7 | if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running."); | 7 | if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running."); |
8 | 8 | ||
9 | swayc_t *container = get_focused_container(&root_container); | 9 | swayc_t *container = current_container; |
10 | close_views(container); | 10 | close_views(container); |
11 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 11 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
12 | } | 12 | } |
diff --git a/sway/commands/layout.c b/sway/commands/layout.c index 570cd207..40ebd590 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c | |||
@@ -16,7 +16,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) { | |||
16 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { | 16 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { |
17 | return error; | 17 | return error; |
18 | } | 18 | } |
19 | swayc_t *parent = get_focused_container(&root_container); | 19 | swayc_t *parent = current_container; |
20 | if (parent->is_floating) { | 20 | if (parent->is_floating) { |
21 | return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); | 21 | return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); |
22 | } | 22 | } |
diff --git a/sway/commands/mark.c b/sway/commands/mark.c new file mode 100644 index 00000000..c1d959df --- /dev/null +++ b/sway/commands/mark.c | |||
@@ -0,0 +1,87 @@ | |||
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 | static void find_marks_callback(swayc_t *container, void *_mark) { | ||
9 | char *mark = (char *)_mark; | ||
10 | |||
11 | int index; | ||
12 | if (container->marks && ((index = list_seq_find(container->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1)) { | ||
13 | list_del(container->marks, index); | ||
14 | } | ||
15 | } | ||
16 | |||
17 | struct cmd_results *cmd_mark(int argc, char **argv) { | ||
18 | struct cmd_results *error = NULL; | ||
19 | if (config->reading) return cmd_results_new(CMD_FAILURE, "mark", "Can't be used in config file."); | ||
20 | if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { | ||
21 | return error; | ||
22 | } | ||
23 | |||
24 | swayc_t *view = current_container; | ||
25 | bool add = false; | ||
26 | bool toggle = false; | ||
27 | |||
28 | if (strcmp(argv[0], "--add") == 0) { | ||
29 | --argc; ++argv; | ||
30 | add = true; | ||
31 | } else if (strcmp(argv[0], "--replace") == 0) { | ||
32 | --argc; ++argv; | ||
33 | } | ||
34 | |||
35 | if (argc && strcmp(argv[0], "--toggle") == 0) { | ||
36 | --argc; ++argv; | ||
37 | toggle = true; | ||
38 | } | ||
39 | |||
40 | if (argc) { | ||
41 | char *mark = join_args(argv, argc); | ||
42 | |||
43 | // Remove all existing marks of this type | ||
44 | container_map(&root_container, find_marks_callback, mark); | ||
45 | |||
46 | if (view->marks) { | ||
47 | if (add) { | ||
48 | int index; | ||
49 | if ((index = list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1) { | ||
50 | if (toggle) { | ||
51 | free(view->marks->items[index]); | ||
52 | list_del(view->marks, index); | ||
53 | |||
54 | if (0 == view->marks->length) { | ||
55 | list_free(view->marks); | ||
56 | view->marks = NULL; | ||
57 | } | ||
58 | } | ||
59 | free(mark); | ||
60 | } else { | ||
61 | list_add(view->marks, mark); | ||
62 | } | ||
63 | } else { | ||
64 | if (toggle && list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark) != -1) { | ||
65 | // Delete the list | ||
66 | list_foreach(view->marks, free); | ||
67 | list_free(view->marks); | ||
68 | view->marks = NULL; | ||
69 | } else { | ||
70 | // Delete and replace with a new list | ||
71 | list_foreach(view->marks, free); | ||
72 | list_free(view->marks); | ||
73 | |||
74 | view->marks = create_list(); | ||
75 | list_add(view->marks, mark); | ||
76 | } | ||
77 | } | ||
78 | } else { | ||
79 | view->marks = create_list(); | ||
80 | list_add(view->marks, mark); | ||
81 | } | ||
82 | } else { | ||
83 | return cmd_results_new(CMD_FAILURE, "mark", | ||
84 | "Expected 'mark [--add|--replace] [--toggle] <mark>'"); | ||
85 | } | ||
86 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
87 | } | ||
diff --git a/sway/commands/move.c b/sway/commands/move.c index 97e10f10..3c47cfe7 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -20,7 +20,7 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
20 | "'move <container|window> to workspace <name>' or " | 20 | "'move <container|window> to workspace <name>' or " |
21 | "'move <container|window|workspace> to output <name|direction>' or " | 21 | "'move <container|window|workspace> to output <name|direction>' or " |
22 | "'move position mouse'"; | 22 | "'move position mouse'"; |
23 | swayc_t *view = get_focused_container(&root_container); | 23 | swayc_t *view = current_container; |
24 | 24 | ||
25 | if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0 )) { | 25 | if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0 )) { |
26 | char *inv; | 26 | char *inv; |
@@ -125,7 +125,7 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
125 | if (view->type != C_CONTAINER && view->type != C_VIEW) { | 125 | if (view->type != C_CONTAINER && view->type != C_VIEW) { |
126 | return cmd_results_new(CMD_FAILURE, "move scratchpad", "Can only move containers and views."); | 126 | return cmd_results_new(CMD_FAILURE, "move scratchpad", "Can only move containers and views."); |
127 | } | 127 | } |
128 | swayc_t *view = get_focused_container(&root_container); | 128 | swayc_t *view = current_container; |
129 | int i; | 129 | int i; |
130 | for (i = 0; i < scratchpad->length; i++) { | 130 | for (i = 0; i < scratchpad->length; i++) { |
131 | if (scratchpad->items[i] == view) { | 131 | if (scratchpad->items[i] == view) { |
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 61af080c..ef52bb07 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -19,7 +19,7 @@ enum resize_dim_types { | |||
19 | }; | 19 | }; |
20 | 20 | ||
21 | static bool set_size_floating(int new_dimension, bool use_width) { | 21 | static bool set_size_floating(int new_dimension, bool use_width) { |
22 | swayc_t *view = get_focused_float(swayc_active_workspace()); | 22 | swayc_t *view = current_container; |
23 | if (view) { | 23 | if (view) { |
24 | if (use_width) { | 24 | if (use_width) { |
25 | int current_width = view->width; | 25 | int current_width = view->width; |
@@ -50,7 +50,7 @@ static bool set_size_floating(int new_dimension, bool use_width) { | |||
50 | } | 50 | } |
51 | 51 | ||
52 | static bool resize_floating(int amount, bool use_width) { | 52 | static bool resize_floating(int amount, bool use_width) { |
53 | swayc_t *view = get_focused_float(swayc_active_workspace()); | 53 | swayc_t *view = current_container; |
54 | 54 | ||
55 | if (view) { | 55 | if (view) { |
56 | if (use_width) { | 56 | if (use_width) { |
@@ -64,7 +64,7 @@ static bool resize_floating(int amount, bool use_width) { | |||
64 | } | 64 | } |
65 | 65 | ||
66 | static bool resize_tiled(int amount, bool use_width) { | 66 | static bool resize_tiled(int amount, bool use_width) { |
67 | swayc_t *container = get_focused_view(swayc_active_workspace()); | 67 | swayc_t *container = current_container; |
68 | swayc_t *parent = container->parent; | 68 | swayc_t *parent = container->parent; |
69 | int idx_focused = 0; | 69 | int idx_focused = 0; |
70 | bool use_major = false; | 70 | bool use_major = false; |
@@ -199,7 +199,7 @@ static bool resize_tiled(int amount, bool use_width) { | |||
199 | 199 | ||
200 | static bool set_size_tiled(int amount, bool use_width) { | 200 | static bool set_size_tiled(int amount, bool use_width) { |
201 | int desired; | 201 | int desired; |
202 | swayc_t *focused = get_focused_view(swayc_active_workspace()); | 202 | swayc_t *focused = current_container; |
203 | 203 | ||
204 | if (use_width) { | 204 | if (use_width) { |
205 | desired = amount - focused->width; | 205 | desired = amount - focused->width; |
@@ -211,7 +211,7 @@ static bool set_size_tiled(int amount, bool use_width) { | |||
211 | } | 211 | } |
212 | 212 | ||
213 | static bool set_size(int dimension, bool use_width) { | 213 | static bool set_size(int dimension, bool use_width) { |
214 | swayc_t *focused = get_focused_view_include_floating(swayc_active_workspace()); | 214 | swayc_t *focused = current_container; |
215 | 215 | ||
216 | if (focused) { | 216 | if (focused) { |
217 | if (focused->is_floating) { | 217 | if (focused->is_floating) { |
@@ -225,7 +225,7 @@ static bool set_size(int dimension, bool use_width) { | |||
225 | } | 225 | } |
226 | 226 | ||
227 | static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) { | 227 | static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) { |
228 | swayc_t *focused = get_focused_view_include_floating(swayc_active_workspace()); | 228 | swayc_t *focused = current_container; |
229 | 229 | ||
230 | // translate "10 ppt" (10%) to appropriate # of pixels in case we need it | 230 | // translate "10 ppt" (10%) to appropriate # of pixels in case we need it |
231 | float ppt_dim = (float)dimension / 100; | 231 | float ppt_dim = (float)dimension / 100; |
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/split.c b/sway/commands/split.c index e7da93d7..e3045a4f 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c | |||
@@ -17,7 +17,7 @@ static struct cmd_results *_do_split(int argc, char **argv, int layout) { | |||
17 | if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) { | 17 | if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) { |
18 | return error; | 18 | return error; |
19 | } | 19 | } |
20 | swayc_t *focused = get_focused_container(&root_container); | 20 | swayc_t *focused = current_container; |
21 | 21 | ||
22 | // Case of floating window, don't split | 22 | // Case of floating window, don't split |
23 | if (focused->is_floating) { | 23 | if (focused->is_floating) { |
@@ -66,7 +66,7 @@ struct cmd_results *cmd_split(int argc, char **argv) { | |||
66 | } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) { | 66 | } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) { |
67 | _do_split(argc - 1, argv + 1, L_HORIZ); | 67 | _do_split(argc - 1, argv + 1, L_HORIZ); |
68 | } else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) { | 68 | } else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) { |
69 | swayc_t *focused = get_focused_container(&root_container); | 69 | swayc_t *focused = current_container; |
70 | if (focused->parent->layout == L_VERT) { | 70 | if (focused->parent->layout == L_VERT) { |
71 | _do_split(argc - 1, argv + 1, L_HORIZ); | 71 | _do_split(argc - 1, argv + 1, L_HORIZ); |
72 | } else { | 72 | } else { |
@@ -89,7 +89,7 @@ struct cmd_results *cmd_splith(int argc, char **argv) { | |||
89 | } | 89 | } |
90 | 90 | ||
91 | struct cmd_results *cmd_splitt(int argc, char **argv) { | 91 | struct cmd_results *cmd_splitt(int argc, char **argv) { |
92 | swayc_t *focused = get_focused_container(&root_container); | 92 | swayc_t *focused = current_container; |
93 | if (focused->parent->layout == L_VERT) { | 93 | if (focused->parent->layout == L_VERT) { |
94 | return _do_split(argc, argv, L_HORIZ); | 94 | return _do_split(argc, argv, L_HORIZ); |
95 | } else { | 95 | } else { |
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c new file mode 100644 index 00000000..ac213261 --- /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 = current_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..ee6d4d1c 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -2,7 +2,7 @@ | |||
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <stdio.h> | 3 | #include <stdio.h> |
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include <regex.h> | 5 | #include <pcre.h> |
6 | #include "sway/criteria.h" | 6 | #include "sway/criteria.h" |
7 | #include "sway/container.h" | 7 | #include "sway/container.h" |
8 | #include "sway/config.h" | 8 | #include "sway/config.h" |
@@ -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, |
@@ -22,16 +23,16 @@ enum criteria_type { // *must* keep in sync with criteria_strings[] | |||
22 | CRIT_LAST | 23 | CRIT_LAST |
23 | }; | 24 | }; |
24 | 25 | ||
25 | // this *must* match the ordering in criteria_type enum | 26 | static const char * const criteria_strings[CRIT_LAST] = { |
26 | static const char * const criteria_strings[] = { | 27 | [CRIT_CLASS] = "class", |
27 | "class", | 28 | [CRIT_CON_MARK] = "con_mark", |
28 | "id", | 29 | [CRIT_ID] = "id", |
29 | "instance", | 30 | [CRIT_INSTANCE] = "instance", |
30 | "title", | 31 | [CRIT_TITLE] = "title", |
31 | "urgent", // either "latest" or "oldest" ... | 32 | [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... |
32 | "window_role", | 33 | [CRIT_WINDOW_ROLE] = "window_role", |
33 | "window_type", | 34 | [CRIT_WINDOW_TYPE] = "window_type", |
34 | "workspace" | 35 | [CRIT_WORKSPACE] = "workspace" |
35 | }; | 36 | }; |
36 | 37 | ||
37 | /** | 38 | /** |
@@ -40,18 +41,13 @@ static const char * const criteria_strings[] = { | |||
40 | */ | 41 | */ |
41 | struct crit_token { | 42 | struct crit_token { |
42 | enum criteria_type type; | 43 | enum criteria_type type; |
43 | regex_t *regex; | 44 | pcre *regex; |
44 | char *raw; | 45 | char *raw; |
45 | }; | 46 | }; |
46 | 47 | ||
47 | static void free_crit_token(struct crit_token *crit) { | 48 | static void free_crit_token(struct crit_token *crit) { |
48 | if (crit->regex) { | 49 | pcre_free(crit->regex); |
49 | regfree(crit->regex); | 50 | free(crit->raw); |
50 | free(crit->regex); | ||
51 | } | ||
52 | if (crit->raw) { | ||
53 | free(crit->raw); | ||
54 | } | ||
55 | free(crit); | 51 | free(crit); |
56 | } | 52 | } |
57 | 53 | ||
@@ -188,18 +184,17 @@ static char *parse_criteria_name(enum criteria_type *type, char *name) { | |||
188 | } | 184 | } |
189 | 185 | ||
190 | // Returns error string on failure or NULL otherwise. | 186 | // Returns error string on failure or NULL otherwise. |
191 | static char *generate_regex(regex_t **regex, char *value) { | 187 | static char *generate_regex(pcre **regex, char *value) { |
192 | *regex = calloc(1, sizeof(regex_t)); | 188 | const char *reg_err; |
193 | int err = regcomp(*regex, value, REG_NOSUB); | 189 | int offset; |
194 | if (err != 0) { | 190 | |
195 | char *reg_err = malloc(64); | 191 | *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL); |
196 | regerror(err, *regex, reg_err, 64); | ||
197 | 192 | ||
193 | if (!*regex) { | ||
198 | const char *fmt = "Regex compilation (for '%s') failed: %s"; | 194 | const char *fmt = "Regex compilation (for '%s') failed: %s"; |
199 | int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; | 195 | int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; |
200 | char *error = malloc(len); | 196 | char *error = malloc(len); |
201 | snprintf(error, len, fmt, value, reg_err); | 197 | snprintf(error, len, fmt, value, reg_err); |
202 | free(reg_err); | ||
203 | return error; | 198 | return error; |
204 | } | 199 | } |
205 | return NULL; | 200 | return NULL; |
@@ -243,6 +238,10 @@ ect_cleanup: | |||
243 | return error; | 238 | return error; |
244 | } | 239 | } |
245 | 240 | ||
241 | static int regex_cmp(const char *item, const pcre *regex) { | ||
242 | return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); | ||
243 | } | ||
244 | |||
246 | // test a single view if it matches list of criteria tokens (all of them). | 245 | // 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) { | 246 | static bool criteria_test(swayc_t *cont, list_t *tokens) { |
248 | if (cont->type != C_VIEW) { | 247 | if (cont->type != C_VIEW) { |
@@ -260,26 +259,34 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
260 | if (focused->class && strcmp(cont->class, focused->class) == 0) { | 259 | if (focused->class && strcmp(cont->class, focused->class) == 0) { |
261 | matches++; | 260 | matches++; |
262 | } | 261 | } |
263 | } else if (crit->regex && regexec(crit->regex, cont->class, 0, NULL, 0) == 0) { | 262 | } else if (crit->regex && regex_cmp(cont->class, crit->regex) == 0) { |
264 | matches++; | 263 | matches++; |
265 | } | 264 | } |
266 | break; | 265 | break; |
266 | case CRIT_CON_MARK: | ||
267 | if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { | ||
268 | // Make sure it isn't matching the NUL string | ||
269 | if ((strcmp(crit->raw, "") == 0) == (list_seq_find(cont->marks, (int (*)(const void *, const void *))strcmp, "") != -1)) { | ||
270 | ++matches; | ||
271 | } | ||
272 | } | ||
273 | break; | ||
267 | case CRIT_ID: | 274 | case CRIT_ID: |
268 | if (!cont->app_id) { | 275 | if (!cont->app_id) { |
269 | // ignore | 276 | // ignore |
270 | } else if (crit->regex && regexec(crit->regex, cont->app_id, 0, NULL, 0) == 0) { | 277 | } else if (crit->regex && regex_cmp(cont->app_id, crit->regex) == 0) { |
271 | matches++; | 278 | matches++; |
272 | } | 279 | } |
273 | break; | 280 | break; |
274 | case CRIT_INSTANCE: | 281 | case CRIT_INSTANCE: |
275 | if (!cont->instance) { | 282 | if (!cont->instance) { |
276 | // ignore | 283 | // ignore |
277 | } else if (strcmp(crit->raw, "focused") == 0) { | 284 | } else if (crit_is_focused(crit->raw)) { |
278 | swayc_t *focused = get_focused_view(&root_container); | 285 | swayc_t *focused = get_focused_view(&root_container); |
279 | if (focused->instance && strcmp(cont->instance, focused->instance) == 0) { | 286 | if (focused->instance && strcmp(cont->instance, focused->instance) == 0) { |
280 | matches++; | 287 | matches++; |
281 | } | 288 | } |
282 | } else if (crit->regex && regexec(crit->regex, cont->instance, 0, NULL, 0) == 0) { | 289 | } else if (crit->regex && regex_cmp(cont->instance, crit->regex) == 0) { |
283 | matches++; | 290 | matches++; |
284 | } | 291 | } |
285 | break; | 292 | break; |
@@ -291,7 +298,7 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
291 | if (focused->name && strcmp(cont->name, focused->name) == 0) { | 298 | if (focused->name && strcmp(cont->name, focused->name) == 0) { |
292 | matches++; | 299 | matches++; |
293 | } | 300 | } |
294 | } else if (crit->regex && regexec(crit->regex, cont->name, 0, NULL, 0) == 0) { | 301 | } else if (crit->regex && regex_cmp(cont->name, crit->regex) == 0) { |
295 | matches++; | 302 | matches++; |
296 | } | 303 | } |
297 | break; | 304 | break; |
@@ -311,7 +318,7 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
311 | if (focused_ws->name && strcmp(cont_ws->name, focused_ws->name) == 0) { | 318 | if (focused_ws->name && strcmp(cont_ws->name, focused_ws->name) == 0) { |
312 | matches++; | 319 | matches++; |
313 | } | 320 | } |
314 | } else if (crit->regex && regexec(crit->regex, cont_ws->name, 0, NULL, 0) == 0) { | 321 | } else if (crit->regex && regex_cmp(cont_ws->name, crit->regex) == 0) { |
315 | matches++; | 322 | matches++; |
316 | } | 323 | } |
317 | break; | 324 | break; |
@@ -362,3 +369,21 @@ list_t *criteria_for(swayc_t *cont) { | |||
362 | } | 369 | } |
363 | return matches; | 370 | return matches; |
364 | } | 371 | } |
372 | |||
373 | struct list_tokens { | ||
374 | list_t *list; | ||
375 | list_t *tokens; | ||
376 | }; | ||
377 | |||
378 | static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) { | ||
379 | if (criteria_test(container, list_tokens->tokens)) { | ||
380 | list_add(list_tokens->list, container); | ||
381 | } | ||
382 | } | ||
383 | list_t *container_for(list_t *tokens) { | ||
384 | struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens}; | ||
385 | |||
386 | container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens); | ||
387 | |||
388 | return list_tokens.list; | ||
389 | } | ||
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index b5f4bb16..67a3cdc8 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -63,6 +63,7 @@ void ipc_client_handle_command(struct ipc_client *client); | |||
63 | bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); | 63 | bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); |
64 | void ipc_get_workspaces_callback(swayc_t *workspace, void *data); | 64 | void ipc_get_workspaces_callback(swayc_t *workspace, void *data); |
65 | void ipc_get_outputs_callback(swayc_t *container, void *data); | 65 | void ipc_get_outputs_callback(swayc_t *container, void *data); |
66 | static void ipc_get_marks_callback(swayc_t *container, void *data); | ||
66 | 67 | ||
67 | void ipc_init(void) { | 68 | void ipc_init(void) { |
68 | ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); | 69 | ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); |
@@ -161,7 +162,8 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { | |||
161 | } | 162 | } |
162 | 163 | ||
163 | int flags; | 164 | int flags; |
164 | if ((flags=fcntl(client_fd, F_GETFD)) == -1 || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { | 165 | if ((flags = fcntl(client_fd, F_GETFD)) == -1 |
166 | || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { | ||
165 | sway_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket"); | 167 | sway_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket"); |
166 | close(client_fd); | 168 | close(client_fd); |
167 | return 0; | 169 | return 0; |
@@ -193,13 +195,12 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { | |||
193 | 195 | ||
194 | if (mask & WLC_EVENT_ERROR) { | 196 | if (mask & WLC_EVENT_ERROR) { |
195 | sway_log(L_ERROR, "IPC Client socket error, removing client"); | 197 | sway_log(L_ERROR, "IPC Client socket error, removing client"); |
196 | client->fd = -1; | ||
197 | ipc_client_disconnect(client); | 198 | ipc_client_disconnect(client); |
198 | return 0; | 199 | return 0; |
199 | } | 200 | } |
200 | 201 | ||
201 | if (mask & WLC_EVENT_HANGUP) { | 202 | if (mask & WLC_EVENT_HANGUP) { |
202 | client->fd = -1; | 203 | sway_log(L_DEBUG, "Client %d hung up", client->fd); |
203 | ipc_client_disconnect(client); | 204 | ipc_client_disconnect(client); |
204 | return 0; | 205 | return 0; |
205 | } | 206 | } |
@@ -456,6 +457,19 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
456 | goto exit_cleanup; | 457 | goto exit_cleanup; |
457 | } | 458 | } |
458 | 459 | ||
460 | case IPC_GET_MARKS: | ||
461 | { | ||
462 | if (!(client->security_policy & IPC_FEATURE_GET_MARKS)) { | ||
463 | goto exit_denied; | ||
464 | } | ||
465 | json_object *marks = json_object_new_array(); | ||
466 | container_map(&root_container, ipc_get_marks_callback, marks); | ||
467 | const char *json_string = json_object_to_json_string(marks); | ||
468 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | ||
469 | json_object_put(marks); | ||
470 | goto exit_cleanup; | ||
471 | } | ||
472 | |||
459 | case IPC_GET_VERSION: | 473 | case IPC_GET_VERSION: |
460 | { | 474 | { |
461 | json_object *version = ipc_json_get_version(); | 475 | json_object *version = ipc_json_get_version(); |
@@ -609,6 +623,16 @@ void ipc_get_outputs_callback(swayc_t *container, void *data) { | |||
609 | } | 623 | } |
610 | } | 624 | } |
611 | 625 | ||
626 | static void ipc_get_marks_callback(swayc_t *container, void *data) { | ||
627 | json_object *object = (json_object *)data; | ||
628 | if (container->marks) { | ||
629 | for (int i = 0; i < container->marks->length; ++i) { | ||
630 | char *mark = (char *)container->marks->items[i]; | ||
631 | json_object_array_add(object, json_object_new_string(mark)); | ||
632 | } | ||
633 | } | ||
634 | } | ||
635 | |||
612 | void ipc_send_event(const char *json_string, enum ipc_command_type event) { | 636 | void ipc_send_event(const char *json_string, enum ipc_command_type event) { |
613 | static struct { | 637 | static struct { |
614 | enum ipc_command_type event; | 638 | enum ipc_command_type event; |
diff --git a/sway/main.c b/sway/main.c index 55b71fa4..b9f8936f 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -11,8 +11,8 @@ | |||
11 | #include <signal.h> | 11 | #include <signal.h> |
12 | #include <unistd.h> | 12 | #include <unistd.h> |
13 | #include <getopt.h> | 13 | #include <getopt.h> |
14 | #include <sys/capability.h> | ||
15 | #ifdef __linux__ | 14 | #ifdef __linux__ |
15 | #include <sys/capability.h> | ||
16 | #include <sys/prctl.h> | 16 | #include <sys/prctl.h> |
17 | #endif | 17 | #endif |
18 | #include "sway/extensions.h" | 18 | #include "sway/extensions.h" |
diff --git a/sway/sway.1.txt b/sway/sway.1.txt index 32519d0e..1a77611d 100644 --- a/sway/sway.1.txt +++ b/sway/sway.1.txt | |||
@@ -48,8 +48,8 @@ providing such a great piece of software, so good that your users would rather | |||
48 | write an entirely new window manager from scratch that behaved _exactly_ like i3 | 48 | write an entirely new window manager from scratch that behaved _exactly_ like i3 |
49 | rather than switch to something else. | 49 | rather than switch to something else. |
50 | 50 | ||
51 | You may run sway from an ongoing x11 session to run it within x. Otherwise, you | 51 | Launch sway directly from a tty or via your favorite Wayland-compatible login |
52 | can run sway on a tty and it will use your outputs directly. | 52 | manager. |
53 | 53 | ||
54 | *Important note for nvidia users*: The proprietary nvidia driver does _not_ have | 54 | *Important note for nvidia users*: The proprietary nvidia driver does _not_ have |
55 | support for Wayland as of 2016-06-10. Use nouveau. | 55 | support for Wayland as of 2016-06-10. Use nouveau. |
diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 5d143d97..d76951b5 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 |
@@ -409,6 +426,20 @@ The string contains one or more (space separated) attribute/value pairs and they | |||
409 | are used by some commands filter which views to execute actions on. All attributes | 426 | are used by some commands filter which views to execute actions on. All attributes |
410 | must match for the criteria string to match. | 427 | must match for the criteria string to match. |
411 | 428 | ||
429 | Criteria may be used with either the **for_window** or **assign** commands to | ||
430 | specify operations to perform on new views. A criteria may also be used to | ||
431 | perform specific commands (ones that normally act upon one window) on all views | ||
432 | that match that criteria. For example: | ||
433 | |||
434 | Focus on a window with the mark "IRC": | ||
435 | [con_mark="IRC"] focus | ||
436 | |||
437 | Kill all windows with the title "Emacs": | ||
438 | [class="Emacs"] kill | ||
439 | |||
440 | Mark all Firefox windows with "Browser": | ||
441 | [class="Firefox"] mark Browser | ||
442 | |||
412 | Currently supported attributes: | 443 | Currently supported attributes: |
413 | 444 | ||
414 | **class**:: | 445 | **class**:: |
@@ -416,6 +447,9 @@ Currently supported attributes: | |||
416 | is _focused_ then the window class must be the same as that of the currently | 447 | is _focused_ then the window class must be the same as that of the currently |
417 | focused window. | 448 | focused window. |
418 | 449 | ||
450 | **con_mark**:: | ||
451 | Compare against the window marks. Can be a regular expression. | ||
452 | |||
419 | **id**:: | 453 | **id**:: |
420 | Compare value against the app id. Can be a regular expression. | 454 | Compare value against the app id. Can be a regular expression. |
421 | 455 | ||