diff options
Diffstat (limited to 'sway')
-rw-r--r-- | sway/CMakeLists.txt | 4 | ||||
-rw-r--r-- | sway/commands.c | 6 | ||||
-rw-r--r-- | sway/commands/bind.c | 5 | ||||
-rw-r--r-- | sway/commands/move.c | 24 | ||||
-rw-r--r-- | sway/commands/output.c | 74 | ||||
-rw-r--r-- | sway/commands/set.c | 2 | ||||
-rw-r--r-- | sway/config.c | 7 | ||||
-rw-r--r-- | sway/container.c | 12 | ||||
-rw-r--r-- | sway/criteria.c | 58 | ||||
-rw-r--r-- | sway/handlers.c | 104 | ||||
-rw-r--r-- | sway/input_state.c | 33 | ||||
-rw-r--r-- | sway/ipc-json.c | 94 | ||||
-rw-r--r-- | sway/ipc-server.c | 108 | ||||
-rw-r--r-- | sway/main.c | 41 | ||||
-rw-r--r-- | sway/sway-security.7.txt | 2 | ||||
-rw-r--r-- | sway/sway.1.txt | 2 | ||||
-rw-r--r-- | sway/workspace.c | 2 |
17 files changed, 416 insertions, 162 deletions
diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt index 11bec4df..48f7a7a8 100644 --- a/sway/CMakeLists.txt +++ b/sway/CMakeLists.txt | |||
@@ -94,6 +94,10 @@ endfunction() | |||
94 | add_config(config config sway) | 94 | add_config(config config sway) |
95 | add_config(00-defaults security.d/00-defaults sway/security.d) | 95 | add_config(00-defaults security.d/00-defaults sway/security.d) |
96 | 96 | ||
97 | if (CMAKE_SYSTEM_NAME STREQUAL FreeBSD) | ||
98 | add_config(10-freebsd security.d/10-freebsd sway/security.d) | ||
99 | endif (CMAKE_SYSTEM_NAME STREQUAL FreeBSD) | ||
100 | |||
97 | if (A2X_FOUND) | 101 | if (A2X_FOUND) |
98 | add_manpage(sway 1) | 102 | add_manpage(sway 1) |
99 | add_manpage(sway 5) | 103 | add_manpage(sway 5) |
diff --git a/sway/commands.c b/sway/commands.c index d55d9a96..c7dbf731 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -458,7 +458,11 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
458 | if (!containers) { | 458 | if (!containers) { |
459 | current_container = get_focused_container(&root_container); | 459 | current_container = get_focused_container(&root_container); |
460 | } else if (containers->length == 0) { | 460 | } else if (containers->length == 0) { |
461 | break; | 461 | if (results) { |
462 | free_cmd_results(results); | ||
463 | } | ||
464 | results = cmd_results_new(CMD_FAILURE, argv[0], "No matching container"); | ||
465 | goto cleanup; | ||
462 | } else { | 466 | } else { |
463 | current_container = (swayc_t *)containers->items[i]; | 467 | current_container = (swayc_t *)containers->items[i]; |
464 | } | 468 | } |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index af5a01e5..d9ea37b7 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -61,10 +61,11 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { | |||
61 | sym = ((char *)split->items[i])[strlen("button")] - '1' + M_LEFT_CLICK; | 61 | sym = ((char *)split->items[i])[strlen("button")] - '1' + M_LEFT_CLICK; |
62 | } | 62 | } |
63 | if (!sym) { | 63 | if (!sym) { |
64 | struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", | ||
65 | "Unknown key '%s'", (char *)split->items[i]); | ||
64 | free_sway_binding(binding); | 66 | free_sway_binding(binding); |
65 | free_flat_list(split); | 67 | free_flat_list(split); |
66 | return cmd_results_new(CMD_INVALID, "bindsym", "Unknown key '%s'", | 68 | return ret; |
67 | (char *)split->items[i]); | ||
68 | } | 69 | } |
69 | xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); | 70 | xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); |
70 | if (!key) { | 71 | if (!key) { |
diff --git a/sway/commands/move.c b/sway/commands/move.c index a38687c1..8d89f2ef 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "sway/output.h" | 7 | #include "sway/output.h" |
8 | #include "sway/workspace.h" | 8 | #include "sway/workspace.h" |
9 | #include "list.h" | 9 | #include "list.h" |
10 | #include "stringop.h" | ||
10 | 11 | ||
11 | struct cmd_results *cmd_move(int argc, char **argv) { | 12 | struct cmd_results *cmd_move(int argc, char **argv) { |
12 | struct cmd_results *error = NULL; | 13 | struct cmd_results *error = NULL; |
@@ -59,18 +60,23 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
59 | return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); | 60 | return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); |
60 | } | 61 | } |
61 | 62 | ||
62 | const char *ws_name = argv[3]; | ||
63 | swayc_t *ws; | 63 | swayc_t *ws; |
64 | if (argc == 5 && strcasecmp(ws_name, "number") == 0) { | 64 | const char *num_name = NULL; |
65 | char *ws_name = NULL; | ||
66 | if (argc == 5 && strcasecmp(argv[3], "number") == 0) { | ||
65 | // move "container to workspace number x" | 67 | // move "container to workspace number x" |
66 | ws_name = argv[4]; | 68 | num_name = argv[4]; |
67 | ws = workspace_by_number(ws_name); | 69 | ws = workspace_by_number(num_name); |
68 | } else { | 70 | } else { |
71 | ws_name = join_args(argv + 3, argc - 3); | ||
69 | ws = workspace_by_name(ws_name); | 72 | ws = workspace_by_name(ws_name); |
70 | } | 73 | } |
71 | 74 | ||
72 | if (ws == NULL) { | 75 | if (ws == NULL) { |
73 | ws = workspace_create(ws_name); | 76 | ws = workspace_create(ws_name ? ws_name : num_name); |
77 | } | ||
78 | if (ws_name) { | ||
79 | free(ws_name); | ||
74 | } | 80 | } |
75 | move_container_to(view, get_focused_container(ws)); | 81 | move_container_to(view, get_focused_container(ws)); |
76 | } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "output") == 0) { | 82 | } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "output") == 0) { |
@@ -161,11 +167,11 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
161 | wlc_view_get_visible_geometry(view->handle, &g); | 167 | wlc_view_get_visible_geometry(view->handle, &g); |
162 | const struct wlc_size *size = wlc_output_get_resolution(output->handle); | 168 | const struct wlc_size *size = wlc_output_get_resolution(output->handle); |
163 | 169 | ||
164 | struct wlc_point origin; | 170 | double x_pos, y_pos; |
165 | wlc_pointer_get_position(&origin); | 171 | wlc_pointer_get_position_v2(&x_pos, &y_pos); |
166 | 172 | ||
167 | int32_t x = origin.x - g.size.w / 2; | 173 | int32_t x = x_pos - g.size.w / 2; |
168 | int32_t y = origin.y - g.size.h / 2; | 174 | int32_t y = y_pos - g.size.h / 2; |
169 | 175 | ||
170 | uint32_t w = size->w - g.size.w; | 176 | uint32_t w = size->w - g.size.w; |
171 | uint32_t h = size->h - g.size.h; | 177 | uint32_t h = size->h - g.size.h; |
diff --git a/sway/commands/output.c b/sway/commands/output.c index e5d4b317..911391d2 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c | |||
@@ -46,7 +46,8 @@ struct cmd_results *cmd_output(int argc, char **argv) { | |||
46 | output->enabled = 0; | 46 | output->enabled = 0; |
47 | } else if (strcasecmp(command, "resolution") == 0 || strcasecmp(command, "res") == 0) { | 47 | } else if (strcasecmp(command, "resolution") == 0 || strcasecmp(command, "res") == 0) { |
48 | if (++i >= argc) { | 48 | if (++i >= argc) { |
49 | return cmd_results_new(CMD_INVALID, "output", "Missing resolution argument."); | 49 | error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument."); |
50 | goto fail; | ||
50 | } | 51 | } |
51 | char *res = argv[i]; | 52 | char *res = argv[i]; |
52 | char *x = strchr(res, 'x'); | 53 | char *x = strchr(res, 'x'); |
@@ -61,7 +62,8 @@ struct cmd_results *cmd_output(int argc, char **argv) { | |||
61 | // Format is 1234 4321 | 62 | // Format is 1234 4321 |
62 | width = atoi(res); | 63 | width = atoi(res); |
63 | if (++i >= argc) { | 64 | if (++i >= argc) { |
64 | return cmd_results_new(CMD_INVALID, "output", "Missing resolution argument (height)."); | 65 | error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument (height)."); |
66 | goto fail; | ||
65 | } | 67 | } |
66 | res = argv[i]; | 68 | res = argv[i]; |
67 | height = atoi(res); | 69 | height = atoi(res); |
@@ -70,7 +72,8 @@ struct cmd_results *cmd_output(int argc, char **argv) { | |||
70 | output->height = height; | 72 | output->height = height; |
71 | } else if (strcasecmp(command, "position") == 0 || strcasecmp(command, "pos") == 0) { | 73 | } else if (strcasecmp(command, "position") == 0 || strcasecmp(command, "pos") == 0) { |
72 | if (++i >= argc) { | 74 | if (++i >= argc) { |
73 | return cmd_results_new(CMD_INVALID, "output", "Missing position argument."); | 75 | error = cmd_results_new(CMD_INVALID, "output", "Missing position argument."); |
76 | goto fail; | ||
74 | } | 77 | } |
75 | char *res = argv[i]; | 78 | char *res = argv[i]; |
76 | char *c = strchr(res, ','); | 79 | char *c = strchr(res, ','); |
@@ -85,7 +88,8 @@ struct cmd_results *cmd_output(int argc, char **argv) { | |||
85 | // Format is 1234 4321 | 88 | // Format is 1234 4321 |
86 | x = atoi(res); | 89 | x = atoi(res); |
87 | if (++i >= argc) { | 90 | if (++i >= argc) { |
88 | return cmd_results_new(CMD_INVALID, "output", "Missing position argument (y)."); | 91 | error = cmd_results_new(CMD_INVALID, "output", "Missing position argument (y)."); |
92 | goto fail; | ||
89 | } | 93 | } |
90 | res = argv[i]; | 94 | res = argv[i]; |
91 | y = atoi(res); | 95 | y = atoi(res); |
@@ -94,25 +98,49 @@ struct cmd_results *cmd_output(int argc, char **argv) { | |||
94 | output->y = y; | 98 | output->y = y; |
95 | } else if (strcasecmp(command, "scale") == 0) { | 99 | } else if (strcasecmp(command, "scale") == 0) { |
96 | if (++i >= argc) { | 100 | if (++i >= argc) { |
97 | return cmd_results_new(CMD_INVALID, "output", "Missing scale parameter."); | 101 | error = cmd_results_new(CMD_INVALID, "output", "Missing scale parameter."); |
102 | goto fail; | ||
98 | } | 103 | } |
99 | output->scale = atoi(argv[i]); | 104 | output->scale = atoi(argv[i]); |
100 | } else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) { | 105 | } else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) { |
101 | wordexp_t p; | 106 | wordexp_t p; |
102 | if (++i >= argc) { | 107 | if (++i >= argc) { |
103 | return cmd_results_new(CMD_INVALID, "output", "Missing background file or color specification."); | 108 | error = cmd_results_new(CMD_INVALID, "output", "Missing background file or color specification."); |
109 | goto fail; | ||
104 | } | 110 | } |
105 | if (i + 1 >= argc) { | 111 | if (i + 1 >= argc) { |
106 | return cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode or `solid_color`."); | 112 | error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode or `solid_color`."); |
113 | goto fail; | ||
107 | } | 114 | } |
108 | if (strcasecmp(argv[argc - 1], "solid_color") == 0) { | 115 | if (strcasecmp(argv[i + 1], "solid_color") == 0) { |
109 | output->background = strdup(argv[argc - 2]); | 116 | output->background = strdup(argv[argc - 2]); |
110 | output->background_option = strdup("solid_color"); | 117 | output->background_option = strdup("solid_color"); |
111 | } else { | 118 | } else { |
112 | char *src = join_args(argv + i, argc - i - 1); | 119 | // argv[i+j]=bg_option |
113 | char *mode = argv[argc - 1]; | 120 | bool valid = false; |
121 | char *mode; | ||
122 | size_t j; | ||
123 | for (j = 0; j < (size_t) (argc - i); ++j) { | ||
124 | mode = argv[i + j]; | ||
125 | for (size_t k = 0; k < sizeof(bg_options) / sizeof(char *); ++k) { | ||
126 | if (strcasecmp(mode, bg_options[k]) == 0) { | ||
127 | valid = true; | ||
128 | break; | ||
129 | } | ||
130 | } | ||
131 | if (valid) { | ||
132 | break; | ||
133 | } | ||
134 | } | ||
135 | if (!valid) { | ||
136 | error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode."); | ||
137 | goto fail; | ||
138 | } | ||
139 | |||
140 | char *src = join_args(argv + i, j); | ||
114 | if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { | 141 | if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { |
115 | return cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src); | 142 | error = cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src); |
143 | goto fail; | ||
116 | } | 144 | } |
117 | free(src); | 145 | free(src); |
118 | src = p.we_wordv[0]; | 146 | src = p.we_wordv[0]; |
@@ -132,27 +160,19 @@ struct cmd_results *cmd_output(int argc, char **argv) { | |||
132 | } | 160 | } |
133 | } | 161 | } |
134 | if (!src || access(src, F_OK) == -1) { | 162 | if (!src || access(src, F_OK) == -1) { |
135 | return cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src); | 163 | error = cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src); |
136 | } | 164 | wordfree(&p); |
137 | for (char *m = mode; *m; ++m) *m = tolower(*m); | 165 | goto fail; |
138 | // Check mode | ||
139 | bool valid = false; | ||
140 | size_t j; | ||
141 | for (j = 0; j < sizeof(bg_options) / sizeof(char *); ++j) { | ||
142 | if (strcasecmp(mode, bg_options[j]) == 0) { | ||
143 | valid = true; | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | if (!valid) { | ||
148 | return cmd_results_new(CMD_INVALID, "output", "Invalid background scaling mode."); | ||
149 | } | 166 | } |
167 | |||
150 | output->background = strdup(src); | 168 | output->background = strdup(src); |
151 | output->background_option = strdup(mode); | 169 | output->background_option = strdup(mode); |
152 | if (src != p.we_wordv[0]) { | 170 | if (src != p.we_wordv[0]) { |
153 | free(src); | 171 | free(src); |
154 | } | 172 | } |
155 | wordfree(&p); | 173 | wordfree(&p); |
174 | |||
175 | i += j; | ||
156 | } | 176 | } |
157 | } | 177 | } |
158 | } | 178 | } |
@@ -192,4 +212,8 @@ struct cmd_results *cmd_output(int argc, char **argv) { | |||
192 | } | 212 | } |
193 | 213 | ||
194 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 214 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
215 | |||
216 | fail: | ||
217 | free_output_config(output); | ||
218 | return error; | ||
195 | } | 219 | } |
diff --git a/sway/commands/set.c b/sway/commands/set.c index e3d08dd3..46fc6d38 100644 --- a/sway/commands/set.c +++ b/sway/commands/set.c | |||
@@ -30,7 +30,7 @@ struct cmd_results *cmd_set(int argc, char **argv) { | |||
30 | if (!tmp) { | 30 | if (!tmp) { |
31 | return cmd_results_new(CMD_FAILURE, "set", "Not possible to create variable $'%s'", argv[0]); | 31 | return cmd_results_new(CMD_FAILURE, "set", "Not possible to create variable $'%s'", argv[0]); |
32 | } | 32 | } |
33 | snprintf(tmp, size, "$%s", argv[0]); | 33 | snprintf(tmp, size+1, "$%s", argv[0]); |
34 | 34 | ||
35 | argv[0] = tmp; | 35 | argv[0] = tmp; |
36 | } | 36 | } |
diff --git a/sway/config.c b/sway/config.c index e0b65615..5b2b6569 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -128,6 +128,8 @@ void free_output_config(struct output_config *oc) { | |||
128 | return; | 128 | return; |
129 | } | 129 | } |
130 | free(oc->name); | 130 | free(oc->name); |
131 | free(oc->background); | ||
132 | free(oc->background_option); | ||
131 | free(oc); | 133 | free(oc); |
132 | } | 134 | } |
133 | 135 | ||
@@ -548,9 +550,12 @@ bool load_main_config(const char *file, bool is_active) { | |||
548 | strcpy(_path, base); | 550 | strcpy(_path, base); |
549 | strcat(_path, ent->d_name); | 551 | strcat(_path, ent->d_name); |
550 | lstat(_path, &s); | 552 | lstat(_path, &s); |
551 | if (S_ISREG(s.st_mode)) { | 553 | if (S_ISREG(s.st_mode) && ent->d_name[0] != '.') { |
552 | list_add(secconfigs, _path); | 554 | list_add(secconfigs, _path); |
553 | } | 555 | } |
556 | else { | ||
557 | free(_path); | ||
558 | } | ||
554 | ent = readdir(dir); | 559 | ent = readdir(dir); |
555 | } | 560 | } |
556 | closedir(dir); | 561 | closedir(dir); |
diff --git a/sway/container.c b/sway/container.c index 358ba767..718608ff 100644 --- a/sway/container.c +++ b/sway/container.c | |||
@@ -516,11 +516,11 @@ swayc_t *destroy_view(swayc_t *view) { | |||
516 | return NULL; | 516 | return NULL; |
517 | } | 517 | } |
518 | sway_log(L_DEBUG, "Destroying view '%p'", view); | 518 | sway_log(L_DEBUG, "Destroying view '%p'", view); |
519 | swayc_t *parent = view->parent; | ||
520 | free_swayc(view); | 519 | free_swayc(view); |
521 | 520 | ||
522 | // Destroy empty containers | 521 | // Destroy empty containers |
523 | if (parent->type == C_CONTAINER) { | 522 | swayc_t *parent = view->parent; |
523 | if (parent && parent->type == C_CONTAINER) { | ||
524 | return destroy_container(parent); | 524 | return destroy_container(parent); |
525 | } | 525 | } |
526 | return parent; | 526 | return parent; |
@@ -707,8 +707,10 @@ swayc_t *container_under_pointer(void) { | |||
707 | if (lookup->children && !lookup->unmanaged) { | 707 | if (lookup->children && !lookup->unmanaged) { |
708 | return NULL; | 708 | return NULL; |
709 | } | 709 | } |
710 | struct wlc_point origin; | 710 | double x, y; |
711 | wlc_pointer_get_position(&origin); | 711 | wlc_pointer_get_position_v2(&x, &y); |
712 | struct wlc_point origin = { .x = x, .y = y }; | ||
713 | |||
712 | while (lookup && lookup->type != C_VIEW) { | 714 | while (lookup && lookup->type != C_VIEW) { |
713 | int i; | 715 | int i; |
714 | int len; | 716 | int len; |
@@ -847,7 +849,6 @@ int swayc_gap(swayc_t *container) { | |||
847 | 849 | ||
848 | void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { | 850 | void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { |
849 | if (container) { | 851 | if (container) { |
850 | f(container, data); | ||
851 | int i; | 852 | int i; |
852 | if (container->children) { | 853 | if (container->children) { |
853 | for (i = 0; i < container->children->length; ++i) { | 854 | for (i = 0; i < container->children->length; ++i) { |
@@ -861,6 +862,7 @@ void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), voi | |||
861 | container_map(child, f, data); | 862 | container_map(child, f, data); |
862 | } | 863 | } |
863 | } | 864 | } |
865 | f(container, data); | ||
864 | } | 866 | } |
865 | } | 867 | } |
866 | 868 | ||
diff --git a/sway/criteria.c b/sway/criteria.c index 04683f66..f5fe40cb 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -12,9 +12,12 @@ | |||
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_ID, | ||
15 | CRIT_CON_MARK, | 16 | CRIT_CON_MARK, |
17 | CRIT_FLOATING, | ||
16 | CRIT_ID, | 18 | CRIT_ID, |
17 | CRIT_INSTANCE, | 19 | CRIT_INSTANCE, |
20 | CRIT_TILING, | ||
18 | CRIT_TITLE, | 21 | CRIT_TITLE, |
19 | CRIT_URGENT, | 22 | CRIT_URGENT, |
20 | CRIT_WINDOW_ROLE, | 23 | CRIT_WINDOW_ROLE, |
@@ -25,9 +28,12 @@ enum criteria_type { // *must* keep in sync with criteria_strings[] | |||
25 | 28 | ||
26 | static const char * const criteria_strings[CRIT_LAST] = { | 29 | static const char * const criteria_strings[CRIT_LAST] = { |
27 | [CRIT_CLASS] = "class", | 30 | [CRIT_CLASS] = "class", |
31 | [CRIT_CON_ID] = "con_id", | ||
28 | [CRIT_CON_MARK] = "con_mark", | 32 | [CRIT_CON_MARK] = "con_mark", |
33 | [CRIT_FLOATING] = "floating", | ||
29 | [CRIT_ID] = "id", | 34 | [CRIT_ID] = "id", |
30 | [CRIT_INSTANCE] = "instance", | 35 | [CRIT_INSTANCE] = "instance", |
36 | [CRIT_TILING] = "tiling", | ||
31 | [CRIT_TITLE] = "title", | 37 | [CRIT_TITLE] = "title", |
32 | [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... | 38 | [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... |
33 | [CRIT_WINDOW_ROLE] = "window_role", | 39 | [CRIT_WINDOW_ROLE] = "window_role", |
@@ -108,6 +114,7 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str | |||
108 | 114 | ||
109 | char **argv = *buf = calloc(max_tokens, sizeof(char*)); | 115 | char **argv = *buf = calloc(max_tokens, sizeof(char*)); |
110 | argv[0] = base; // this needs to be freed by caller | 116 | argv[0] = base; // this needs to be freed by caller |
117 | bool quoted = true; | ||
111 | 118 | ||
112 | *argc = 1; // uneven = name, even = value | 119 | *argc = 1; // uneven = name, even = value |
113 | while (*head && *argc < max_tokens) { | 120 | while (*head && *argc < max_tokens) { |
@@ -128,7 +135,8 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str | |||
128 | if (*(namep) == ' ') { | 135 | if (*(namep) == ' ') { |
129 | namep = strrchr(namep, ' ') + 1; | 136 | namep = strrchr(namep, ' ') + 1; |
130 | } | 137 | } |
131 | argv[(*argc)++] = namep; | 138 | argv[*argc] = namep; |
139 | *argc += 1; | ||
132 | } | 140 | } |
133 | } else if (*head == '"') { | 141 | } else if (*head == '"') { |
134 | if (*argc % 2 != 0) { | 142 | if (*argc % 2 != 0) { |
@@ -137,21 +145,38 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str | |||
137 | "Found quoted value where it was not expected"); | 145 | "Found quoted value where it was not expected"); |
138 | } else if (!valp) { // value starts here | 146 | } else if (!valp) { // value starts here |
139 | valp = head + 1; | 147 | valp = head + 1; |
148 | quoted = true; | ||
140 | } else { | 149 | } else { |
141 | // value ends here | 150 | // value ends here |
142 | argv[(*argc)++] = valp; | 151 | argv[*argc] = valp; |
152 | *argc += 1; | ||
143 | *head = '\0'; | 153 | *head = '\0'; |
144 | valp = NULL; | 154 | valp = NULL; |
145 | namep = head + 1; | 155 | namep = head + 1; |
146 | } | 156 | } |
147 | } else if (*argc % 2 == 0 && !valp && *head != ' ') { | 157 | } else if (*argc % 2 == 0 && *head != ' ') { |
148 | // We're expecting a quoted value, haven't found one yet, and this | 158 | // parse unquoted values |
149 | // is not an empty space. | 159 | if (!valp) { |
150 | return strdup("Unable to parse criteria: " | 160 | quoted = false; |
151 | "Names must be unquoted, values must be quoted"); | 161 | valp = head; // value starts here |
162 | } | ||
163 | } else if (valp && !quoted && *head == ' ') { | ||
164 | // value ends here | ||
165 | argv[*argc] = valp; | ||
166 | *argc += 1; | ||
167 | *head = '\0'; | ||
168 | valp = NULL; | ||
169 | namep = head + 1; | ||
152 | } | 170 | } |
153 | head++; | 171 | head++; |
154 | } | 172 | } |
173 | |||
174 | // catch last unquoted value if needed | ||
175 | if (valp && !quoted && !*head) { | ||
176 | argv[*argc] = valp; | ||
177 | *argc += 1; | ||
178 | } | ||
179 | |||
155 | return NULL; | 180 | return NULL; |
156 | } | 181 | } |
157 | 182 | ||
@@ -263,6 +288,15 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
263 | matches++; | 288 | matches++; |
264 | } | 289 | } |
265 | break; | 290 | break; |
291 | case CRIT_CON_ID: { | ||
292 | char *endptr; | ||
293 | size_t crit_id = strtoul(crit->raw, &endptr, 10); | ||
294 | |||
295 | if (*endptr == 0 && cont->id == crit_id) { | ||
296 | ++matches; | ||
297 | } | ||
298 | break; | ||
299 | } | ||
266 | case CRIT_CON_MARK: | 300 | 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)) { | 301 | 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 | 302 | // Make sure it isn't matching the NUL string |
@@ -271,6 +305,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
271 | } | 305 | } |
272 | } | 306 | } |
273 | break; | 307 | break; |
308 | case CRIT_FLOATING: | ||
309 | if (cont->is_floating) { | ||
310 | matches++; | ||
311 | } | ||
312 | break; | ||
274 | case CRIT_ID: | 313 | case CRIT_ID: |
275 | if (!cont->app_id) { | 314 | if (!cont->app_id) { |
276 | // ignore | 315 | // ignore |
@@ -290,6 +329,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
290 | matches++; | 329 | matches++; |
291 | } | 330 | } |
292 | break; | 331 | break; |
332 | case CRIT_TILING: | ||
333 | if (!cont->is_floating) { | ||
334 | matches++; | ||
335 | } | ||
336 | break; | ||
293 | case CRIT_TITLE: | 337 | case CRIT_TITLE: |
294 | if (!cont->name) { | 338 | if (!cont->name) { |
295 | // ignore | 339 | // ignore |
diff --git a/sway/handlers.c b/sway/handlers.c index 052789ca..d37142a9 100644 --- a/sway/handlers.c +++ b/sway/handlers.c | |||
@@ -452,6 +452,7 @@ static bool handle_view_created(wlc_handle handle) { | |||
452 | wlc_view_focus(handle); | 452 | wlc_view_focus(handle); |
453 | wlc_view_bring_to_front(handle); | 453 | wlc_view_bring_to_front(handle); |
454 | newview = new_floating_view(handle); | 454 | newview = new_floating_view(handle); |
455 | /* fallthrough */ | ||
455 | case WLC_BIT_POPUP: | 456 | case WLC_BIT_POPUP: |
456 | wlc_view_bring_to_front(handle); | 457 | wlc_view_bring_to_front(handle); |
457 | break; | 458 | break; |
@@ -552,21 +553,24 @@ static void handle_view_destroyed(wlc_handle handle) { | |||
552 | bool fullscreen = swayc_is_fullscreen(view); | 553 | bool fullscreen = swayc_is_fullscreen(view); |
553 | remove_view_from_scratchpad(view); | 554 | remove_view_from_scratchpad(view); |
554 | swayc_t *parent = destroy_view(view); | 555 | swayc_t *parent = destroy_view(view); |
555 | if (fullscreen) { | 556 | if (parent) { |
556 | parent->fullscreen = NULL; | 557 | if (fullscreen) { |
557 | } | 558 | parent->fullscreen = NULL; |
559 | } | ||
558 | 560 | ||
559 | // Destroy empty workspaces | 561 | ipc_event_window(parent, "close"); |
560 | if (parent->type == C_WORKSPACE && | ||
561 | parent->children->length == 0 && | ||
562 | parent->floating->length == 0 && | ||
563 | swayc_active_workspace() != parent && | ||
564 | !parent->visible) { | ||
565 | parent = destroy_workspace(parent); | ||
566 | } | ||
567 | 562 | ||
568 | arrange_windows(parent, -1, -1); | 563 | // Destroy empty workspaces |
569 | ipc_event_window(parent, "close"); | 564 | if (parent->type == C_WORKSPACE && |
565 | parent->children->length == 0 && | ||
566 | parent->floating->length == 0 && | ||
567 | swayc_active_workspace() != parent && | ||
568 | !parent->visible) { | ||
569 | parent = destroy_workspace(parent); | ||
570 | } | ||
571 | |||
572 | arrange_windows(parent, -1, -1); | ||
573 | } | ||
570 | } else { | 574 | } else { |
571 | // Is it unmanaged? | 575 | // Is it unmanaged? |
572 | int i; | 576 | int i; |
@@ -582,6 +586,15 @@ static void handle_view_destroyed(wlc_handle handle) { | |||
582 | } | 586 | } |
583 | } | 587 | } |
584 | } | 588 | } |
589 | // Is it in the scratchpad? | ||
590 | for (i = 0; i < scratchpad->length; ++i) { | ||
591 | swayc_t *item = scratchpad->items[i]; | ||
592 | if (item->handle == handle) { | ||
593 | list_del(scratchpad, i); | ||
594 | destroy_view(item); | ||
595 | break; | ||
596 | } | ||
597 | } | ||
585 | } | 598 | } |
586 | set_focused_container(get_focused_view(&root_container)); | 599 | set_focused_container(get_focused_view(&root_container)); |
587 | } | 600 | } |
@@ -805,11 +818,11 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier | |||
805 | struct sway_binding *binding = mode->bindings->items[i]; | 818 | struct sway_binding *binding = mode->bindings->items[i]; |
806 | if ((modifiers->mods ^ binding->modifiers) == 0) { | 819 | if ((modifiers->mods ^ binding->modifiers) == 0) { |
807 | switch (state) { | 820 | switch (state) { |
808 | case WLC_KEY_STATE_PRESSED: { | 821 | case WLC_KEY_STATE_PRESSED: |
809 | if (!binding->release && valid_bindsym(binding)) { | 822 | if (!binding->release && valid_bindsym(binding)) { |
810 | list_add(candidates, binding); | 823 | list_add(candidates, binding); |
811 | } | 824 | } |
812 | } | 825 | break; |
813 | case WLC_KEY_STATE_RELEASED: | 826 | case WLC_KEY_STATE_RELEASED: |
814 | if (binding->release && handle_bindsym_release(binding)) { | 827 | if (binding->release && handle_bindsym_release(binding)) { |
815 | list_free(candidates); | 828 | list_free(candidates); |
@@ -842,12 +855,13 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier | |||
842 | return EVENT_PASSTHROUGH; | 855 | return EVENT_PASSTHROUGH; |
843 | } | 856 | } |
844 | 857 | ||
845 | static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_point *origin) { | 858 | static bool handle_pointer_motion(wlc_handle handle, uint32_t time, double x, double y) { |
846 | if (desktop_shell.is_locked) { | 859 | if (desktop_shell.is_locked) { |
847 | return EVENT_PASSTHROUGH; | 860 | return EVENT_PASSTHROUGH; |
848 | } | 861 | } |
849 | 862 | ||
850 | struct wlc_point new_origin = *origin; | 863 | double new_x = x; |
864 | double new_y = y; | ||
851 | // Switch to adjacent output if touching output edge. | 865 | // Switch to adjacent output if touching output edge. |
852 | // | 866 | // |
853 | // Since this doesn't currently support moving windows between outputs we | 867 | // Since this doesn't currently support moving windows between outputs we |
@@ -856,45 +870,43 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct | |||
856 | !pointer_state.left.held && !pointer_state.right.held && !pointer_state.scroll.held) { | 870 | !pointer_state.left.held && !pointer_state.right.held && !pointer_state.scroll.held) { |
857 | 871 | ||
858 | swayc_t *output = swayc_active_output(), *adjacent = NULL; | 872 | swayc_t *output = swayc_active_output(), *adjacent = NULL; |
859 | struct wlc_point abs_pos = *origin; | 873 | struct wlc_point abs_pos = { .x = x + output->x, .y = y + output->y }; |
860 | abs_pos.x += output->x; | 874 | if (x <= 0) { // Left edge |
861 | abs_pos.y += output->y; | ||
862 | if (origin->x == 0) { // Left edge | ||
863 | if ((adjacent = swayc_adjacent_output(output, MOVE_LEFT, &abs_pos, false))) { | 875 | if ((adjacent = swayc_adjacent_output(output, MOVE_LEFT, &abs_pos, false))) { |
864 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | 876 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { |
865 | new_origin.x = adjacent->width; | 877 | new_x = adjacent->width; |
866 | // adjust for differently aligned outputs (well, this is | 878 | // adjust for differently aligned outputs (well, this is |
867 | // only correct when the two outputs have the same | 879 | // only correct when the two outputs have the same |
868 | // resolution or the same dpi I guess, it should take | 880 | // resolution or the same dpi I guess, it should take |
869 | // physical attributes into account) | 881 | // physical attributes into account) |
870 | new_origin.y += (output->y - adjacent->y); | 882 | new_y += (output->y - adjacent->y); |
871 | } | 883 | } |
872 | } | 884 | } |
873 | } else if ((double)origin->x == output->width) { // Right edge | 885 | } else if (x >= output->width) { // Right edge |
874 | if ((adjacent = swayc_adjacent_output(output, MOVE_RIGHT, &abs_pos, false))) { | 886 | if ((adjacent = swayc_adjacent_output(output, MOVE_RIGHT, &abs_pos, false))) { |
875 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | 887 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { |
876 | new_origin.x = 0; | 888 | new_x = 0; |
877 | new_origin.y += (output->y - adjacent->y); | 889 | new_y += (output->y - adjacent->y); |
878 | } | 890 | } |
879 | } | 891 | } |
880 | } else if (origin->y == 0) { // Top edge | 892 | } else if (y <= 0) { // Top edge |
881 | if ((adjacent = swayc_adjacent_output(output, MOVE_UP, &abs_pos, false))) { | 893 | if ((adjacent = swayc_adjacent_output(output, MOVE_UP, &abs_pos, false))) { |
882 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | 894 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { |
883 | new_origin.y = adjacent->height; | 895 | new_y = adjacent->height; |
884 | new_origin.x += (output->x - adjacent->x); | 896 | new_x += (output->x - adjacent->x); |
885 | } | 897 | } |
886 | } | 898 | } |
887 | } else if ((double)origin->y == output->height) { // Bottom edge | 899 | } else if (y >= output->height) { // Bottom edge |
888 | if ((adjacent = swayc_adjacent_output(output, MOVE_DOWN, &abs_pos, false))) { | 900 | if ((adjacent = swayc_adjacent_output(output, MOVE_DOWN, &abs_pos, false))) { |
889 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | 901 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { |
890 | new_origin.y = 0; | 902 | new_y = 0; |
891 | new_origin.x += (output->x - adjacent->x); | 903 | new_x += (output->x - adjacent->x); |
892 | } | 904 | } |
893 | } | 905 | } |
894 | } | 906 | } |
895 | } | 907 | } |
896 | 908 | ||
897 | pointer_position_set(&new_origin, false); | 909 | pointer_position_set(new_x, new_y, false); |
898 | 910 | ||
899 | swayc_t *focused = get_focused_container(&root_container); | 911 | swayc_t *focused = get_focused_container(&root_container); |
900 | if (focused->type == C_VIEW) { | 912 | if (focused->type == C_VIEW) { |
@@ -935,15 +947,15 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w | |||
935 | struct sway_binding *binding = mode->bindings->items[i]; | 947 | struct sway_binding *binding = mode->bindings->items[i]; |
936 | if ((modifiers->mods ^ binding->modifiers) == 0) { | 948 | if ((modifiers->mods ^ binding->modifiers) == 0) { |
937 | switch (state) { | 949 | switch (state) { |
938 | case WLC_BUTTON_STATE_PRESSED: { | 950 | case WLC_BUTTON_STATE_PRESSED: |
939 | if (!binding->release && handle_bindsym(binding, button, 0)) { | 951 | if (!binding->release && handle_bindsym(binding, button, 0)) { |
940 | return EVENT_HANDLED; | 952 | return EVENT_HANDLED; |
941 | } | 953 | } |
954 | break; | ||
955 | case WLC_BUTTON_STATE_RELEASED: | ||
956 | if (binding->release && handle_bindsym(binding, button, 0)) { | ||
957 | return EVENT_HANDLED; | ||
942 | } | 958 | } |
943 | case WLC_BUTTON_STATE_RELEASED: | ||
944 | if (binding->release && handle_bindsym(binding, button, 0)) { | ||
945 | return EVENT_HANDLED; | ||
946 | } | ||
947 | break; | 959 | break; |
948 | } | 960 | } |
949 | } | 961 | } |
@@ -1084,16 +1096,8 @@ bool handle_pointer_scroll(wlc_handle view, uint32_t time, const struct wlc_modi | |||
1084 | return EVENT_PASSTHROUGH; | 1096 | return EVENT_PASSTHROUGH; |
1085 | } | 1097 | } |
1086 | 1098 | ||
1087 | static void clip_test_cb(void *data, const char *type, int fd) { | ||
1088 | const char *str = data; | ||
1089 | write(fd, str, strlen(str)); | ||
1090 | close(fd); | ||
1091 | } | ||
1092 | |||
1093 | static void handle_wlc_ready(void) { | 1099 | static void handle_wlc_ready(void) { |
1094 | sway_log(L_DEBUG, "Compositor is ready, executing cmds in queue"); | 1100 | sway_log(L_DEBUG, "Compositor is ready, executing cmds in queue"); |
1095 | const char *type = "text/plain;charset=utf-8"; | ||
1096 | wlc_set_selection("test", &type, 1, &clip_test_cb); | ||
1097 | // Execute commands until there are none left | 1101 | // Execute commands until there are none left |
1098 | config->active = true; | 1102 | config->active = true; |
1099 | while (config->cmd_queue->length) { | 1103 | while (config->cmd_queue->length) { |
@@ -1122,7 +1126,7 @@ void register_wlc_handlers() { | |||
1122 | wlc_set_view_request_state_cb(handle_view_state_request); | 1126 | wlc_set_view_request_state_cb(handle_view_state_request); |
1123 | wlc_set_view_properties_updated_cb(handle_view_properties_updated); | 1127 | wlc_set_view_properties_updated_cb(handle_view_properties_updated); |
1124 | wlc_set_keyboard_key_cb(handle_key); | 1128 | wlc_set_keyboard_key_cb(handle_key); |
1125 | wlc_set_pointer_motion_cb(handle_pointer_motion); | 1129 | wlc_set_pointer_motion_cb_v2(handle_pointer_motion); |
1126 | wlc_set_pointer_button_cb(handle_pointer_button); | 1130 | wlc_set_pointer_button_cb(handle_pointer_button); |
1127 | wlc_set_pointer_scroll_cb(handle_pointer_scroll); | 1131 | wlc_set_pointer_scroll_cb(handle_pointer_scroll); |
1128 | wlc_set_compositor_ready_cb(handle_wlc_ready); | 1132 | wlc_set_compositor_ready_cb(handle_wlc_ready); |
diff --git a/sway/input_state.c b/sway/input_state.c index 68df17de..04aafd37 100644 --- a/sway/input_state.c +++ b/sway/input_state.c | |||
@@ -202,13 +202,13 @@ static void reset_initial_sibling(void) { | |||
202 | pointer_state.mode = 0; | 202 | pointer_state.mode = 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | void pointer_position_set(struct wlc_point *new_origin, bool force_focus) { | 205 | void pointer_position_set(double new_x, double new_y, bool force_focus) { |
206 | struct wlc_point origin; | 206 | double x, y; |
207 | wlc_pointer_get_position(&origin); | 207 | wlc_pointer_get_position_v2(&x, &y); |
208 | pointer_state.delta.x = new_origin->x - origin.x; | 208 | pointer_state.delta.x = new_x - x; |
209 | pointer_state.delta.y = new_origin->y - origin.y; | 209 | pointer_state.delta.y = new_y - y; |
210 | 210 | ||
211 | wlc_pointer_set_position(new_origin); | 211 | wlc_pointer_set_position_v2(new_x, new_y); |
212 | 212 | ||
213 | // Update view under pointer | 213 | // Update view under pointer |
214 | swayc_t *prev_view = pointer_state.view; | 214 | swayc_t *prev_view = pointer_state.view; |
@@ -226,10 +226,7 @@ void pointer_position_set(struct wlc_point *new_origin, bool force_focus) { | |||
226 | } | 226 | } |
227 | 227 | ||
228 | void center_pointer_on(swayc_t *view) { | 228 | void center_pointer_on(swayc_t *view) { |
229 | struct wlc_point new_origin; | 229 | pointer_position_set(view->x + view->width/2, view->y + view->height/2, true); |
230 | new_origin.x = view->x + view->width/2; | ||
231 | new_origin.y = view->y + view->height/2; | ||
232 | pointer_position_set(&new_origin, true); | ||
233 | } | 230 | } |
234 | 231 | ||
235 | // Mode set left/right click | 232 | // Mode set left/right click |
@@ -269,10 +266,10 @@ static void pointer_mode_set_resizing(void) { | |||
269 | int midway_x = initial.ptr->x + initial.ptr->width/2; | 266 | int midway_x = initial.ptr->x + initial.ptr->width/2; |
270 | int midway_y = initial.ptr->y + initial.ptr->height/2; | 267 | int midway_y = initial.ptr->y + initial.ptr->height/2; |
271 | 268 | ||
272 | struct wlc_point origin; | 269 | double x, y; |
273 | wlc_pointer_get_position(&origin); | 270 | wlc_pointer_get_position_v2(&x, &y); |
274 | lock.left = origin.x > midway_x; | 271 | lock.left = x > midway_x; |
275 | lock.top = origin.y > midway_y; | 272 | lock.top = y > midway_y; |
276 | 273 | ||
277 | if (initial.ptr->is_floating) { | 274 | if (initial.ptr->is_floating) { |
278 | pointer_state.mode = M_RESIZING | M_FLOATING; | 275 | pointer_state.mode = M_RESIZING | M_FLOATING; |
@@ -346,10 +343,10 @@ void pointer_mode_update(void) { | |||
346 | pointer_state.mode = 0; | 343 | pointer_state.mode = 0; |
347 | return; | 344 | return; |
348 | } | 345 | } |
349 | struct wlc_point origin; | 346 | double x, y; |
350 | wlc_pointer_get_position(&origin); | 347 | wlc_pointer_get_position_v2(&x, &y); |
351 | int dx = origin.x; | 348 | int dx = x; |
352 | int dy = origin.y; | 349 | int dy = y; |
353 | 350 | ||
354 | switch (pointer_state.mode) { | 351 | switch (pointer_state.mode) { |
355 | case M_FLOATING | M_DRAGGING: | 352 | case M_FLOATING | M_DRAGGING: |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 31de53f0..6ab63c75 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -138,7 +138,6 @@ static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) | |||
138 | 138 | ||
139 | json_object_object_add(object, "num", json_object_new_int(num)); | 139 | json_object_object_add(object, "num", json_object_new_int(num)); |
140 | json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); | 140 | json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); |
141 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
142 | json_object_object_add(object, "type", json_object_new_string("workspace")); | 141 | json_object_object_add(object, "type", json_object_new_string("workspace")); |
143 | json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); | 142 | json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); |
144 | } | 143 | } |
@@ -156,38 +155,14 @@ static const char *ipc_json_get_scratchpad_state(swayc_t *c) { | |||
156 | 155 | ||
157 | static void ipc_json_describe_view(swayc_t *c, json_object *object) { | 156 | static void ipc_json_describe_view(swayc_t *c, json_object *object) { |
158 | json_object *props = json_object_new_object(); | 157 | json_object *props = json_object_new_object(); |
159 | float percent = ipc_json_child_percentage(c); | ||
160 | const char *layout = (c->parent->type == C_CONTAINER) ? | ||
161 | ipc_json_layout_description(c->parent->layout) : "none"; | ||
162 | const char *last_layout = (c->parent->type == C_CONTAINER) ? | ||
163 | ipc_json_layout_description(c->parent->prev_layout) : "none"; | ||
164 | wlc_handle parent = wlc_view_get_parent(c->handle); | ||
165 | |||
166 | json_object_object_add(object, "type", json_object_new_string((c->is_floating) ? "floating_con" : "con")); | 158 | json_object_object_add(object, "type", json_object_new_string((c->is_floating) ? "floating_con" : "con")); |
167 | 159 | ||
160 | wlc_handle parent = wlc_view_get_parent(c->handle); | ||
168 | json_object_object_add(object, "scratchpad_state", | 161 | json_object_object_add(object, "scratchpad_state", |
169 | json_object_new_string(ipc_json_get_scratchpad_state(c))); | 162 | json_object_new_string(ipc_json_get_scratchpad_state(c))); |
170 | json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); | ||
171 | // TODO: make urgency actually work once Sway supports it | ||
172 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
173 | json_object_object_add(object, "layout", | ||
174 | (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); | ||
175 | json_object_object_add(object, "last_split_layout", | ||
176 | (strcmp(last_layout, "null") == 0) ? NULL : json_object_new_string(last_layout)); | ||
177 | json_object_object_add(object, "workspace_layout", | ||
178 | json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout))); | ||
179 | |||
180 | json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c))); | ||
181 | json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness)); | ||
182 | |||
183 | json_object_object_add(object, "rect", ipc_json_create_rect(c)); | ||
184 | json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry)); | ||
185 | json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry)); | ||
186 | json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry)); | ||
187 | 163 | ||
188 | json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); | 164 | json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); |
189 | 165 | ||
190 | json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat | ||
191 | json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) : | 166 | json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) : |
192 | c->app_id ? json_object_new_string(c->app_id) : NULL); | 167 | c->app_id ? json_object_new_string(c->app_id) : NULL); |
193 | json_object_object_add(props, "instance", c->instance ? json_object_new_string(c->instance) : | 168 | json_object_object_add(props, "instance", c->instance ? json_object_new_string(c->instance) : |
@@ -203,9 +178,29 @@ static void ipc_json_describe_view(swayc_t *c, json_object *object) { | |||
203 | c->is_floating ? "auto_on" : "auto_off")); // we can't state the cause | 178 | c->is_floating ? "auto_on" : "auto_off")); // we can't state the cause |
204 | 179 | ||
205 | json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL); | 180 | json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL); |
181 | |||
182 | if (c->parent) { | ||
183 | const char *layout = (c->parent->type == C_CONTAINER) ? | ||
184 | ipc_json_layout_description(c->parent->layout) : "none"; | ||
185 | const char *last_layout = (c->parent->type == C_CONTAINER) ? | ||
186 | ipc_json_layout_description(c->parent->prev_layout) : "none"; | ||
187 | json_object_object_add(object, "layout", | ||
188 | (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); | ||
189 | json_object_object_add(object, "last_split_layout", | ||
190 | (strcmp(last_layout, "null") == 0) ? NULL : json_object_new_string(last_layout)); | ||
191 | json_object_object_add(object, "workspace_layout", | ||
192 | json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout))); | ||
193 | } | ||
194 | } | ||
195 | |||
196 | static void ipc_json_describe_root(swayc_t *c, json_object *object) { | ||
197 | json_object_object_add(object, "type", json_object_new_string("root")); | ||
198 | json_object_object_add(object, "layout", json_object_new_string("splith")); | ||
206 | } | 199 | } |
207 | 200 | ||
208 | json_object *ipc_json_describe_container(swayc_t *c) { | 201 | json_object *ipc_json_describe_container(swayc_t *c) { |
202 | float percent = ipc_json_child_percentage(c); | ||
203 | |||
209 | if (!(sway_assert(c, "Container must not be null."))) { | 204 | if (!(sway_assert(c, "Container must not be null."))) { |
210 | return NULL; | 205 | return NULL; |
211 | } | 206 | } |
@@ -218,9 +213,19 @@ json_object *ipc_json_describe_container(swayc_t *c) { | |||
218 | json_object_object_add(object, "visible", json_object_new_boolean(c->visible)); | 213 | json_object_object_add(object, "visible", json_object_new_boolean(c->visible)); |
219 | json_object_object_add(object, "focused", json_object_new_boolean(c == current_focus)); | 214 | json_object_object_add(object, "focused", json_object_new_boolean(c == current_focus)); |
220 | 215 | ||
216 | json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c))); | ||
217 | json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry)); | ||
218 | json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry)); | ||
219 | json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry)); | ||
220 | json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); | ||
221 | json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat | ||
222 | // TODO: make urgency actually work once Sway supports it | ||
223 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
224 | json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness)); | ||
225 | |||
221 | switch (c->type) { | 226 | switch (c->type) { |
222 | case C_ROOT: | 227 | case C_ROOT: |
223 | json_object_object_add(object, "type", json_object_new_string("root")); | 228 | ipc_json_describe_root(c, object); |
224 | break; | 229 | break; |
225 | 230 | ||
226 | case C_OUTPUT: | 231 | case C_OUTPUT: |
@@ -451,21 +456,50 @@ json_object *ipc_json_describe_container_recursive(swayc_t *c) { | |||
451 | int i; | 456 | int i; |
452 | 457 | ||
453 | json_object *floating = json_object_new_array(); | 458 | json_object *floating = json_object_new_array(); |
454 | if (c->type != C_VIEW && c->floating && c->floating->length > 0) { | 459 | if (c->type != C_VIEW && c->floating) { |
455 | for (i = 0; i < c->floating->length; ++i) { | 460 | for (i = 0; i < c->floating->length; ++i) { |
456 | json_object_array_add(floating, ipc_json_describe_container_recursive(c->floating->items[i])); | 461 | swayc_t *item = c->floating->items[i]; |
462 | json_object_array_add(floating, ipc_json_describe_container_recursive(item)); | ||
457 | } | 463 | } |
458 | } | 464 | } |
459 | json_object_object_add(object, "floating_nodes", floating); | 465 | json_object_object_add(object, "floating_nodes", floating); |
460 | 466 | ||
461 | json_object *children = json_object_new_array(); | 467 | json_object *children = json_object_new_array(); |
462 | if (c->type != C_VIEW && c->children && c->children->length > 0) { | 468 | if (c->type != C_VIEW && c->children) { |
463 | for (i = 0; i < c->children->length; ++i) { | 469 | for (i = 0; i < c->children->length; ++i) { |
464 | json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); | 470 | json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); |
465 | } | 471 | } |
466 | } | 472 | } |
467 | json_object_object_add(object, "nodes", children); | 473 | json_object_object_add(object, "nodes", children); |
468 | 474 | ||
475 | json_object *focus = json_object_new_array(); | ||
476 | if (c->type != C_VIEW) { | ||
477 | if (c->focused) { | ||
478 | json_object_array_add(focus, json_object_new_double(c->focused->id)); | ||
479 | } | ||
480 | if (c->floating) { | ||
481 | for (i = 0; i < c->floating->length; ++i) { | ||
482 | swayc_t *item = c->floating->items[i]; | ||
483 | if (item == c->focused) { | ||
484 | continue; | ||
485 | } | ||
486 | |||
487 | json_object_array_add(focus, json_object_new_double(item->id)); | ||
488 | } | ||
489 | } | ||
490 | if (c->children) { | ||
491 | for (i = 0; i < c->children->length; ++i) { | ||
492 | swayc_t *item = c->children->items[i]; | ||
493 | if (item == c->focused) { | ||
494 | continue; | ||
495 | } | ||
496 | |||
497 | json_object_array_add(focus, json_object_new_double(item->id)); | ||
498 | } | ||
499 | } | ||
500 | } | ||
501 | json_object_object_add(object, "focus", focus); | ||
502 | |||
469 | if (c->type == C_ROOT) { | 503 | if (c->type == C_ROOT) { |
470 | json_object *scratchpad_json = json_object_new_array(); | 504 | json_object *scratchpad_json = json_object_new_array(); |
471 | if (scratchpad->length > 0) { | 505 | if (scratchpad->length > 0) { |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 5e1e93ce..4ce2b7eb 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -41,11 +41,15 @@ static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; | |||
41 | 41 | ||
42 | struct ipc_client { | 42 | struct ipc_client { |
43 | struct wlc_event_source *event_source; | 43 | struct wlc_event_source *event_source; |
44 | struct wlc_event_source *writable_event_source; | ||
44 | int fd; | 45 | int fd; |
45 | uint32_t payload_length; | 46 | uint32_t payload_length; |
46 | uint32_t security_policy; | 47 | uint32_t security_policy; |
47 | enum ipc_command_type current_command; | 48 | enum ipc_command_type current_command; |
48 | enum ipc_command_type subscribed_events; | 49 | enum ipc_command_type subscribed_events; |
50 | size_t write_buffer_len; | ||
51 | size_t write_buffer_size; | ||
52 | char *write_buffer; | ||
49 | }; | 53 | }; |
50 | 54 | ||
51 | static list_t *ipc_get_pixel_requests = NULL; | 55 | static list_t *ipc_get_pixel_requests = NULL; |
@@ -72,6 +76,7 @@ struct get_clipboard_request { | |||
72 | struct sockaddr_un *ipc_user_sockaddr(void); | 76 | struct sockaddr_un *ipc_user_sockaddr(void); |
73 | int ipc_handle_connection(int fd, uint32_t mask, void *data); | 77 | int ipc_handle_connection(int fd, uint32_t mask, void *data); |
74 | int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); | 78 | int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); |
79 | int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data); | ||
75 | void ipc_client_disconnect(struct ipc_client *client); | 80 | void ipc_client_disconnect(struct ipc_client *client); |
76 | void ipc_client_handle_command(struct ipc_client *client); | 81 | void ipc_client_handle_command(struct ipc_client *client); |
77 | bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); | 82 | bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); |
@@ -182,6 +187,12 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { | |||
182 | close(client_fd); | 187 | close(client_fd); |
183 | return 0; | 188 | return 0; |
184 | } | 189 | } |
190 | if ((flags = fcntl(client_fd, F_GETFL)) == -1 | ||
191 | || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { | ||
192 | sway_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket"); | ||
193 | close(client_fd); | ||
194 | return 0; | ||
195 | } | ||
185 | 196 | ||
186 | struct ipc_client* client = malloc(sizeof(struct ipc_client)); | 197 | struct ipc_client* client = malloc(sizeof(struct ipc_client)); |
187 | if (!client) { | 198 | if (!client) { |
@@ -193,10 +204,22 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { | |||
193 | client->fd = client_fd; | 204 | client->fd = client_fd; |
194 | client->subscribed_events = 0; | 205 | client->subscribed_events = 0; |
195 | client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client); | 206 | client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client); |
207 | client->writable_event_source = NULL; | ||
208 | |||
209 | client->write_buffer_size = 128; | ||
210 | client->write_buffer_len = 0; | ||
211 | client->write_buffer = malloc(client->write_buffer_size); | ||
212 | if (!client->write_buffer) { | ||
213 | sway_log(L_ERROR, "Unable to allocate ipc client write buffer"); | ||
214 | close(client_fd); | ||
215 | return 0; | ||
216 | } | ||
196 | 217 | ||
197 | pid_t pid = get_client_pid(client->fd); | 218 | pid_t pid = get_client_pid(client->fd); |
198 | client->security_policy = get_ipc_policy_mask(pid); | 219 | client->security_policy = get_ipc_policy_mask(pid); |
199 | 220 | ||
221 | sway_log(L_DEBUG, "New client: fd %d, pid %d", client_fd, pid); | ||
222 | |||
200 | list_add(ipc_client_list, client); | 223 | list_add(ipc_client_list, client); |
201 | 224 | ||
202 | return 0; | 225 | return 0; |
@@ -219,6 +242,8 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { | |||
219 | return 0; | 242 | return 0; |
220 | } | 243 | } |
221 | 244 | ||
245 | sway_log(L_DEBUG, "Client %d readable", client->fd); | ||
246 | |||
222 | int read_available; | 247 | int read_available; |
223 | if (ioctl(client_fd, FIONREAD, &read_available) == -1) { | 248 | if (ioctl(client_fd, FIONREAD, &read_available) == -1) { |
224 | sway_log_errno(L_INFO, "Unable to read IPC socket buffer size"); | 249 | sway_log_errno(L_INFO, "Unable to read IPC socket buffer size"); |
@@ -240,6 +265,7 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { | |||
240 | 265 | ||
241 | uint8_t buf[ipc_header_size]; | 266 | uint8_t buf[ipc_header_size]; |
242 | uint32_t *buf32 = (uint32_t*)(buf + sizeof(ipc_magic)); | 267 | uint32_t *buf32 = (uint32_t*)(buf + sizeof(ipc_magic)); |
268 | // Should be fully available, because read_available >= ipc_header_size | ||
243 | ssize_t received = recv(client_fd, buf, ipc_header_size, 0); | 269 | ssize_t received = recv(client_fd, buf, ipc_header_size, 0); |
244 | if (received == -1) { | 270 | if (received == -1) { |
245 | sway_log_errno(L_INFO, "Unable to receive header from IPC client"); | 271 | sway_log_errno(L_INFO, "Unable to receive header from IPC client"); |
@@ -263,6 +289,48 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { | |||
263 | return 0; | 289 | return 0; |
264 | } | 290 | } |
265 | 291 | ||
292 | int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { | ||
293 | struct ipc_client *client = data; | ||
294 | |||
295 | if (mask & WLC_EVENT_ERROR) { | ||
296 | sway_log(L_ERROR, "IPC Client socket error, removing client"); | ||
297 | ipc_client_disconnect(client); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | if (mask & WLC_EVENT_HANGUP) { | ||
302 | sway_log(L_DEBUG, "Client %d hung up", client->fd); | ||
303 | ipc_client_disconnect(client); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | if (client->write_buffer_len <= 0) { | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | sway_log(L_DEBUG, "Client %d writable", client->fd); | ||
312 | |||
313 | ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len); | ||
314 | |||
315 | if (written == -1 && errno == EAGAIN) { | ||
316 | return 0; | ||
317 | } else if (written == -1) { | ||
318 | sway_log_errno(L_INFO, "Unable to send data from queue to IPC client"); | ||
319 | ipc_client_disconnect(client); | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | memmove(client->write_buffer, client->write_buffer + written, client->write_buffer_len - written); | ||
324 | client->write_buffer_len -= written; | ||
325 | |||
326 | if (client->write_buffer_len == 0 && client->writable_event_source) { | ||
327 | wlc_event_source_remove(client->writable_event_source); | ||
328 | client->writable_event_source = NULL; | ||
329 | } | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
266 | void ipc_client_disconnect(struct ipc_client *client) { | 334 | void ipc_client_disconnect(struct ipc_client *client) { |
267 | if (!sway_assert(client != NULL, "client != NULL")) { | 335 | if (!sway_assert(client != NULL, "client != NULL")) { |
268 | return; | 336 | return; |
@@ -274,9 +342,13 @@ void ipc_client_disconnect(struct ipc_client *client) { | |||
274 | 342 | ||
275 | sway_log(L_INFO, "IPC Client %d disconnected", client->fd); | 343 | sway_log(L_INFO, "IPC Client %d disconnected", client->fd); |
276 | wlc_event_source_remove(client->event_source); | 344 | wlc_event_source_remove(client->event_source); |
345 | if (client->writable_event_source) { | ||
346 | wlc_event_source_remove(client->writable_event_source); | ||
347 | } | ||
277 | int i = 0; | 348 | int i = 0; |
278 | while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++; | 349 | while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++; |
279 | list_del(ipc_client_list, i); | 350 | list_del(ipc_client_list, i); |
351 | free(client->write_buffer); | ||
280 | close(client->fd); | 352 | close(client->fd); |
281 | free(client); | 353 | free(client); |
282 | } | 354 | } |
@@ -608,6 +680,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
608 | return; | 680 | return; |
609 | } | 681 | } |
610 | if (client->payload_length > 0) { | 682 | if (client->payload_length > 0) { |
683 | // Payload should be fully available | ||
611 | ssize_t received = recv(client->fd, buf, client->payload_length, 0); | 684 | ssize_t received = recv(client->fd, buf, client->payload_length, 0); |
612 | if (received == -1) | 685 | if (received == -1) |
613 | { | 686 | { |
@@ -874,17 +947,36 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay | |||
874 | data32[0] = payload_length; | 947 | data32[0] = payload_length; |
875 | data32[1] = client->current_command; | 948 | data32[1] = client->current_command; |
876 | 949 | ||
877 | if (write(client->fd, data, ipc_header_size) == -1) { | 950 | while (client->write_buffer_len + ipc_header_size + payload_length >= |
878 | sway_log_errno(L_INFO, "Unable to send header to IPC client"); | 951 | client->write_buffer_size) { |
952 | client->write_buffer_size *= 2; | ||
953 | } | ||
954 | |||
955 | // TODO: reduce the limit back to 4 MB when screenshooter is implemented | ||
956 | if (client->write_buffer_size > (1 << 28)) { // 256 MB | ||
957 | sway_log(L_ERROR, "Client write buffer too big, disconnecting client"); | ||
958 | ipc_client_disconnect(client); | ||
879 | return false; | 959 | return false; |
880 | } | 960 | } |
881 | 961 | ||
882 | if (write(client->fd, payload, payload_length) == -1) { | 962 | char *new_buffer = realloc(client->write_buffer, client->write_buffer_size); |
883 | sway_log_errno(L_INFO, "Unable to send payload to IPC client"); | 963 | if (!new_buffer) { |
964 | sway_log(L_ERROR, "Unable to reallocate ipc client write buffer"); | ||
965 | ipc_client_disconnect(client); | ||
884 | return false; | 966 | return false; |
885 | } | 967 | } |
968 | client->write_buffer = new_buffer; | ||
969 | |||
970 | memcpy(client->write_buffer + client->write_buffer_len, data, ipc_header_size); | ||
971 | client->write_buffer_len += ipc_header_size; | ||
972 | memcpy(client->write_buffer + client->write_buffer_len, payload, payload_length); | ||
973 | client->write_buffer_len += payload_length; | ||
974 | |||
975 | if (!client->writable_event_source) { | ||
976 | client->writable_event_source = wlc_event_loop_add_fd(client->fd, WLC_EVENT_WRITABLE, ipc_client_handle_writable, client); | ||
977 | } | ||
886 | 978 | ||
887 | sway_log(L_DEBUG, "Send IPC reply: %s", payload); | 979 | sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); |
888 | 980 | ||
889 | return true; | 981 | return true; |
890 | } | 982 | } |
@@ -984,11 +1076,7 @@ void ipc_event_window(swayc_t *window, const char *change) { | |||
984 | sway_log(L_DEBUG, "Sending window::%s event", change); | 1076 | sway_log(L_DEBUG, "Sending window::%s event", change); |
985 | json_object *obj = json_object_new_object(); | 1077 | json_object *obj = json_object_new_object(); |
986 | json_object_object_add(obj, "change", json_object_new_string(change)); | 1078 | json_object_object_add(obj, "change", json_object_new_string(change)); |
987 | if (strcmp(change, "close") == 0 || !window) { | 1079 | json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); |
988 | json_object_object_add(obj, "container", NULL); | ||
989 | } else { | ||
990 | json_object_object_add(obj, "container", ipc_json_describe_container(window)); | ||
991 | } | ||
992 | 1080 | ||
993 | const char *json_string = json_object_to_json_string(obj); | 1081 | const char *json_string = json_object_to_json_string(obj); |
994 | ipc_send_event(json_string, IPC_EVENT_WINDOW); | 1082 | ipc_send_event(json_string, IPC_EVENT_WINDOW); |
diff --git a/sway/main.c b/sway/main.c index 82375e0b..6d13955c 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -53,6 +53,46 @@ static void wlc_log_handler(enum wlc_log_type type, const char *str) { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | void detect_raspi() { | ||
57 | bool raspi = false; | ||
58 | FILE *f = fopen("/sys/firmware/devicetree/base/model", "r"); | ||
59 | if (!f) { | ||
60 | return; | ||
61 | } | ||
62 | char *line; | ||
63 | while(!feof(f)) { | ||
64 | if (!(line = read_line(f))) { | ||
65 | break; | ||
66 | } | ||
67 | if (strstr(line, "Raspberry Pi")) { | ||
68 | raspi = true; | ||
69 | } | ||
70 | free(line); | ||
71 | } | ||
72 | fclose(f); | ||
73 | FILE *g = fopen("/proc/modules", "r"); | ||
74 | if (!g) { | ||
75 | return; | ||
76 | } | ||
77 | bool vc4 = false; | ||
78 | while (!feof(g)) { | ||
79 | if (!(line = read_line(g))) { | ||
80 | break; | ||
81 | } | ||
82 | if (strstr(line, "vc4")) { | ||
83 | vc4 = true; | ||
84 | } | ||
85 | free(line); | ||
86 | } | ||
87 | fclose(g); | ||
88 | if (!vc4 && raspi) { | ||
89 | fprintf(stderr, "\x1B[1;31mWarning: You have a " | ||
90 | "Raspberry Pi, but the vc4 Module is " | ||
91 | "not loaded! Set 'dtoverlay=vc4-kms-v3d'" | ||
92 | "in /boot/config.txt and reboot.\x1B[0m\n"); | ||
93 | } | ||
94 | } | ||
95 | |||
56 | void detect_proprietary() { | 96 | void detect_proprietary() { |
57 | FILE *f = fopen("/proc/modules", "r"); | 97 | FILE *f = fopen("/proc/modules", "r"); |
58 | if (!f) { | 98 | if (!f) { |
@@ -366,6 +406,7 @@ int main(int argc, char **argv) { | |||
366 | log_distro(); | 406 | log_distro(); |
367 | log_env(); | 407 | log_env(); |
368 | detect_proprietary(); | 408 | detect_proprietary(); |
409 | detect_raspi(); | ||
369 | 410 | ||
370 | input_devices = create_list(); | 411 | input_devices = create_list(); |
371 | 412 | ||
diff --git a/sway/sway-security.7.txt b/sway/sway-security.7.txt index ec6df1f3..aee3793c 100644 --- a/sway/sway-security.7.txt +++ b/sway/sway-security.7.txt | |||
@@ -237,4 +237,4 @@ Authors | |||
237 | ------- | 237 | ------- |
238 | Maintained by Drew DeVault <sir@cmpwn.com>, who is assisted by other open | 238 | Maintained by Drew DeVault <sir@cmpwn.com>, who is assisted by other open |
239 | source contributors. For more information about sway development, see | 239 | source contributors. For more information about sway development, see |
240 | <https://github.com/SirCmpwn/sway>. | 240 | <https://github.com/swaywm/sway>. |
diff --git a/sway/sway.1.txt b/sway/sway.1.txt index bc827bd5..4a1aef99 100644 --- a/sway/sway.1.txt +++ b/sway/sway.1.txt | |||
@@ -119,7 +119,7 @@ Authors | |||
119 | 119 | ||
120 | Maintained by Drew DeVault <sir@cmpwn.com>, who is assisted by other open | 120 | Maintained by Drew DeVault <sir@cmpwn.com>, who is assisted by other open |
121 | source contributors. For more information about sway development, see | 121 | source contributors. For more information about sway development, see |
122 | <https://github.com/SirCmpwn/sway>. | 122 | <https://github.com/swaywm/sway>. |
123 | 123 | ||
124 | See Also | 124 | See Also |
125 | -------- | 125 | -------- |
diff --git a/sway/workspace.c b/sway/workspace.c index 29cacce9..e0367190 100644 --- a/sway/workspace.c +++ b/sway/workspace.c | |||
@@ -61,7 +61,7 @@ char *workspace_next_name(const char *output_name) { | |||
61 | // workspace n | 61 | // workspace n |
62 | char *cmd = argsep(&cmdlist, " "); | 62 | char *cmd = argsep(&cmdlist, " "); |
63 | if (cmdlist) { | 63 | if (cmdlist) { |
64 | name = argsep(&cmdlist, " ,;"); | 64 | name = argsep(&cmdlist, ",;"); |
65 | } | 65 | } |
66 | 66 | ||
67 | if (strcmp("workspace", cmd) == 0 && name) { | 67 | if (strcmp("workspace", cmd) == 0 && name) { |