summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2017-04-10 07:17:47 -0400
committerLibravatar GitHub <noreply@github.com>2017-04-10 07:17:47 -0400
commit5d3a02a7c624bbef07b1b228eb1bb60fade5248c (patch)
tree35860f43beb1ce46de5a3d780ca33830d4bc9ba4
parentAdd pretty printing to swaymsg (diff)
parentMerge pull request #1150 from JerziKaminsky/cmake_find_libcap (diff)
downloadsway-5d3a02a7c624bbef07b1b228eb1bb60fade5248c.tar.gz
sway-5d3a02a7c624bbef07b1b228eb1bb60fade5248c.tar.zst
sway-5d3a02a7c624bbef07b1b228eb1bb60fade5248c.zip
Merge branch 'master' into pretty-print-swaymsg
-rw-r--r--.travis.yml1
-rw-r--r--CMake/FindLibcap.cmake56
-rw-r--r--CMakeLists.txt1
-rw-r--r--include/sway/commands.h6
-rw-r--r--include/sway/config.h1
-rw-r--r--include/sway/container.h5
-rw-r--r--include/sway/criteria.h3
-rw-r--r--sway/border.c23
-rw-r--r--sway/commands.c82
-rw-r--r--sway/commands/border.c2
-rw-r--r--sway/commands/floating.c2
-rw-r--r--sway/commands/focus.c3
-rw-r--r--sway/commands/fullscreen.c2
-rw-r--r--sway/commands/kill.c2
-rw-r--r--sway/commands/layout.c2
-rw-r--r--sway/commands/mark.c87
-rw-r--r--sway/commands/move.c4
-rw-r--r--sway/commands/resize.c12
-rw-r--r--sway/commands/show_marks.c13
-rw-r--r--sway/commands/split.c6
-rw-r--r--sway/commands/unmark.c31
-rw-r--r--sway/config.c1
-rw-r--r--sway/container.c4
-rw-r--r--sway/criteria.c89
-rw-r--r--sway/ipc-server.c30
-rw-r--r--sway/main.c2
-rw-r--r--sway/sway.1.txt4
-rw-r--r--sway/sway.5.txt34
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
34include(FeatureSummary)
35set_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
39find_package(PkgConfig)
40pkg_check_modules(PC_CAP QUIET Libcap)
41find_library(Libcap_LIBRARIES NAMES cap HINTS ${PC_CAP_LIBRARY_DIRS})
42find_path(Libcap_INCLUDE_DIRS sys/capability.h HINTS ${PC_CAP_INCLUDE_DIRS})
43
44set(Libcap_VERSION ${PC_CAP_VERSION})
45string(REPLACE "." ";" VERSION_LIST "${PC_CAP_VERSION}")
46
47LIST(LENGTH VERSION_LIST n)
48if (n EQUAL 2)
49 list(GET VERSION_LIST 0 Libcap_VERSION_MAJOR)
50 list(GET VERSION_LIST 1 Libcap_VERSION_MINOR)
51endif ()
52
53include(FindPackageHandleStandardArgs)
54find_package_handle_standard_args(Libcap DEFAULT_MSG Libcap_INCLUDE_DIRS Libcap_LIBRARIES)
55mark_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)
66find_package(PAM) 66find_package(PAM)
67 67
68find_package(LibInput REQUIRED) 68find_package(LibInput REQUIRED)
69find_package(Libcap REQUIRED)
69 70
70if (CMAKE_SYSTEM_NAME STREQUAL FreeBSD) 71if (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.
9extern 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;
126sway_cmd cmd_kill; 129sway_cmd cmd_kill;
127sway_cmd cmd_layout; 130sway_cmd cmd_layout;
128sway_cmd cmd_log_colors; 131sway_cmd cmd_log_colors;
132sway_cmd cmd_mark;
129sway_cmd cmd_mode; 133sway_cmd cmd_mode;
130sway_cmd cmd_mouse_warping; 134sway_cmd cmd_mouse_warping;
131sway_cmd cmd_move; 135sway_cmd cmd_move;
@@ -140,12 +144,14 @@ sway_cmd cmd_resize;
140sway_cmd cmd_scratchpad; 144sway_cmd cmd_scratchpad;
141sway_cmd cmd_seamless_mouse; 145sway_cmd cmd_seamless_mouse;
142sway_cmd cmd_set; 146sway_cmd cmd_set;
147sway_cmd cmd_show_marks;
143sway_cmd cmd_smart_gaps; 148sway_cmd cmd_smart_gaps;
144sway_cmd cmd_split; 149sway_cmd cmd_split;
145sway_cmd cmd_splith; 150sway_cmd cmd_splith;
146sway_cmd cmd_splitt; 151sway_cmd cmd_splitt;
147sway_cmd cmd_splitv; 152sway_cmd cmd_splitv;
148sway_cmd cmd_sticky; 153sway_cmd cmd_sticky;
154sway_cmd cmd_unmark;
149sway_cmd cmd_workspace; 155sway_cmd cmd_workspace;
150sway_cmd cmd_ws_auto_back_and_forth; 156sway_cmd cmd_ws_auto_back_and_forth;
151sway_cmd cmd_workspace_layout; 157sway_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
170enum visibility_mask { 175enum 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.
34list_t *criteria_for(swayc_t *cont); 34list_t *criteria_for(swayc_t *cont);
35 35
36// Returns a list of all containers that match the given list of tokens.
37list_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
44int sp_index = 0; 44int sp_index = 0;
45 45
46swayc_t *current_container = NULL;
47
46// Returns error object, or NULL if check succeeds. 48// Returns error object, or NULL if check succeeds.
47struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { 49struct 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
8static 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
17struct 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
21static bool set_size_floating(int new_dimension, bool use_width) { 21static 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
52static bool resize_floating(int amount, bool use_width) { 52static 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
66static bool resize_tiled(int amount, bool use_width) { 66static 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
200static bool set_size_tiled(int amount, bool use_width) { 200static 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
213static bool set_size(int dimension, bool use_width) { 213static 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
227static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) { 227static 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
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/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
91struct cmd_results *cmd_splitt(int argc, char **argv) { 91struct 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
7struct 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
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,
@@ -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 26static const char * const criteria_strings[CRIT_LAST] = {
26static 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 */
41struct crit_token { 42struct 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
47static void free_crit_token(struct crit_token *crit) { 48static 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.
191static char *generate_regex(regex_t **regex, char *value) { 187static 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, &reg_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
241static 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).
247static bool criteria_test(swayc_t *cont, list_t *tokens) { 246static 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
373struct list_tokens {
374 list_t *list;
375 list_t *tokens;
376};
377
378static 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}
383list_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);
63bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); 63bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
64void ipc_get_workspaces_callback(swayc_t *workspace, void *data); 64void ipc_get_workspaces_callback(swayc_t *workspace, void *data);
65void ipc_get_outputs_callback(swayc_t *container, void *data); 65void ipc_get_outputs_callback(swayc_t *container, void *data);
66static void ipc_get_marks_callback(swayc_t *container, void *data);
66 67
67void ipc_init(void) { 68void 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
626static 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
612void ipc_send_event(const char *json_string, enum ipc_command_type event) { 636void 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
48write an entirely new window manager from scratch that behaved _exactly_ like i3 48write an entirely new window manager from scratch that behaved _exactly_ like i3
49rather than switch to something else. 49rather than switch to something else.
50 50
51You may run sway from an ongoing x11 session to run it within x. Otherwise, you 51Launch sway directly from a tty or via your favorite Wayland-compatible login
52can run sway on a tty and it will use your outputs directly. 52manager.
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
55support for Wayland as of 2016-06-10. Use nouveau. 55support 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
409are used by some commands filter which views to execute actions on. All attributes 426are used by some commands filter which views to execute actions on. All attributes
410must match for the criteria string to match. 427must match for the criteria string to match.
411 428
429Criteria may be used with either the **for_window** or **assign** commands to
430specify operations to perform on new views. A criteria may also be used to
431perform specific commands (ones that normally act upon one window) on all views
432that match that criteria. For example:
433
434Focus on a window with the mark "IRC":
435 [con_mark="IRC"] focus
436
437Kill all windows with the title "Emacs":
438 [class="Emacs"] kill
439
440Mark all Firefox windows with "Browser":
441 [class="Firefox"] mark Browser
442
412Currently supported attributes: 443Currently 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