aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/CMakeLists.txt4
-rw-r--r--sway/commands.c6
-rw-r--r--sway/commands/bind.c5
-rw-r--r--sway/commands/move.c24
-rw-r--r--sway/commands/output.c74
-rw-r--r--sway/commands/set.c2
-rw-r--r--sway/config.c7
-rw-r--r--sway/container.c12
-rw-r--r--sway/criteria.c58
-rw-r--r--sway/handlers.c104
-rw-r--r--sway/input_state.c33
-rw-r--r--sway/ipc-json.c94
-rw-r--r--sway/ipc-server.c108
-rw-r--r--sway/main.c41
-rw-r--r--sway/sway-security.7.txt2
-rw-r--r--sway/sway.1.txt2
-rw-r--r--sway/workspace.c2
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()
add_config(config config sway)
add_config(00-defaults security.d/00-defaults sway/security.d)
+if (CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+ add_config(10-freebsd security.d/10-freebsd sway/security.d)
+endif (CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+
if (A2X_FOUND)
add_manpage(sway 1)
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) {
if (!containers) {
current_container = get_focused_container(&root_container);
} else if (containers->length == 0) {
- break;
+ if (results) {
+ free_cmd_results(results);
+ }
+ results = cmd_results_new(CMD_FAILURE, argv[0], "No matching container");
+ goto cleanup;
} else {
current_container = (swayc_t *)containers->items[i];
}
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) {
sym = ((char *)split->items[i])[strlen("button")] - '1' + M_LEFT_CLICK;
}
if (!sym) {
+ struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym",
+ "Unknown key '%s'", (char *)split->items[i]);
free_sway_binding(binding);
free_flat_list(split);
- return cmd_results_new(CMD_INVALID, "bindsym", "Unknown key '%s'",
- (char *)split->items[i]);
+ return ret;
}
xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t));
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 @@
#include "sway/output.h"
#include "sway/workspace.h"
#include "list.h"
+#include "stringop.h"
struct cmd_results *cmd_move(int argc, char **argv) {
struct cmd_results *error = NULL;
@@ -59,18 +60,23 @@ struct cmd_results *cmd_move(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views.");
}
- const char *ws_name = argv[3];
swayc_t *ws;
- if (argc == 5 && strcasecmp(ws_name, "number") == 0) {
+ const char *num_name = NULL;
+ char *ws_name = NULL;
+ if (argc == 5 && strcasecmp(argv[3], "number") == 0) {
// move "container to workspace number x"
- ws_name = argv[4];
- ws = workspace_by_number(ws_name);
+ num_name = argv[4];
+ ws = workspace_by_number(num_name);
} else {
+ ws_name = join_args(argv + 3, argc - 3);
ws = workspace_by_name(ws_name);
}
if (ws == NULL) {
- ws = workspace_create(ws_name);
+ ws = workspace_create(ws_name ? ws_name : num_name);
+ }
+ if (ws_name) {
+ free(ws_name);
}
move_container_to(view, get_focused_container(ws));
} 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) {
wlc_view_get_visible_geometry(view->handle, &g);
const struct wlc_size *size = wlc_output_get_resolution(output->handle);
- struct wlc_point origin;
- wlc_pointer_get_position(&origin);
+ double x_pos, y_pos;
+ wlc_pointer_get_position_v2(&x_pos, &y_pos);
- int32_t x = origin.x - g.size.w / 2;
- int32_t y = origin.y - g.size.h / 2;
+ int32_t x = x_pos - g.size.w / 2;
+ int32_t y = y_pos - g.size.h / 2;
uint32_t w = size->w - g.size.w;
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) {
output->enabled = 0;
} else if (strcasecmp(command, "resolution") == 0 || strcasecmp(command, "res") == 0) {
if (++i >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing resolution argument.");
+ error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument.");
+ goto fail;
}
char *res = argv[i];
char *x = strchr(res, 'x');
@@ -61,7 +62,8 @@ struct cmd_results *cmd_output(int argc, char **argv) {
// Format is 1234 4321
width = atoi(res);
if (++i >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing resolution argument (height).");
+ error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument (height).");
+ goto fail;
}
res = argv[i];
height = atoi(res);
@@ -70,7 +72,8 @@ struct cmd_results *cmd_output(int argc, char **argv) {
output->height = height;
} else if (strcasecmp(command, "position") == 0 || strcasecmp(command, "pos") == 0) {
if (++i >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing position argument.");
+ error = cmd_results_new(CMD_INVALID, "output", "Missing position argument.");
+ goto fail;
}
char *res = argv[i];
char *c = strchr(res, ',');
@@ -85,7 +88,8 @@ struct cmd_results *cmd_output(int argc, char **argv) {
// Format is 1234 4321
x = atoi(res);
if (++i >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing position argument (y).");
+ error = cmd_results_new(CMD_INVALID, "output", "Missing position argument (y).");
+ goto fail;
}
res = argv[i];
y = atoi(res);
@@ -94,25 +98,49 @@ struct cmd_results *cmd_output(int argc, char **argv) {
output->y = y;
} else if (strcasecmp(command, "scale") == 0) {
if (++i >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing scale parameter.");
+ error = cmd_results_new(CMD_INVALID, "output", "Missing scale parameter.");
+ goto fail;
}
output->scale = atoi(argv[i]);
} else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) {
wordexp_t p;
if (++i >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing background file or color specification.");
+ error = cmd_results_new(CMD_INVALID, "output", "Missing background file or color specification.");
+ goto fail;
}
if (i + 1 >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode or `solid_color`.");
+ error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode or `solid_color`.");
+ goto fail;
}
- if (strcasecmp(argv[argc - 1], "solid_color") == 0) {
+ if (strcasecmp(argv[i + 1], "solid_color") == 0) {
output->background = strdup(argv[argc - 2]);
output->background_option = strdup("solid_color");
} else {
- char *src = join_args(argv + i, argc - i - 1);
- char *mode = argv[argc - 1];
+ // argv[i+j]=bg_option
+ bool valid = false;
+ char *mode;
+ size_t j;
+ for (j = 0; j < (size_t) (argc - i); ++j) {
+ mode = argv[i + j];
+ for (size_t k = 0; k < sizeof(bg_options) / sizeof(char *); ++k) {
+ if (strcasecmp(mode, bg_options[k]) == 0) {
+ valid = true;
+ break;
+ }
+ }
+ if (valid) {
+ break;
+ }
+ }
+ if (!valid) {
+ error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode.");
+ goto fail;
+ }
+
+ char *src = join_args(argv + i, j);
if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
- return cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src);
+ error = cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src);
+ goto fail;
}
free(src);
src = p.we_wordv[0];
@@ -132,27 +160,19 @@ struct cmd_results *cmd_output(int argc, char **argv) {
}
}
if (!src || access(src, F_OK) == -1) {
- return cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src);
- }
- for (char *m = mode; *m; ++m) *m = tolower(*m);
- // Check mode
- bool valid = false;
- size_t j;
- for (j = 0; j < sizeof(bg_options) / sizeof(char *); ++j) {
- if (strcasecmp(mode, bg_options[j]) == 0) {
- valid = true;
- break;
- }
- }
- if (!valid) {
- return cmd_results_new(CMD_INVALID, "output", "Invalid background scaling mode.");
+ error = cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src);
+ wordfree(&p);
+ goto fail;
}
+
output->background = strdup(src);
output->background_option = strdup(mode);
if (src != p.we_wordv[0]) {
free(src);
}
wordfree(&p);
+
+ i += j;
}
}
}
@@ -192,4 +212,8 @@ struct cmd_results *cmd_output(int argc, char **argv) {
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+
+fail:
+ free_output_config(output);
+ return error;
}
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) {
if (!tmp) {
return cmd_results_new(CMD_FAILURE, "set", "Not possible to create variable $'%s'", argv[0]);
}
- snprintf(tmp, size, "$%s", argv[0]);
+ snprintf(tmp, size+1, "$%s", argv[0]);
argv[0] = tmp;
}
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) {
return;
}
free(oc->name);
+ free(oc->background);
+ free(oc->background_option);
free(oc);
}
@@ -548,9 +550,12 @@ bool load_main_config(const char *file, bool is_active) {
strcpy(_path, base);
strcat(_path, ent->d_name);
lstat(_path, &s);
- if (S_ISREG(s.st_mode)) {
+ if (S_ISREG(s.st_mode) && ent->d_name[0] != '.') {
list_add(secconfigs, _path);
}
+ else {
+ free(_path);
+ }
ent = readdir(dir);
}
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) {
return NULL;
}
sway_log(L_DEBUG, "Destroying view '%p'", view);
- swayc_t *parent = view->parent;
free_swayc(view);
// Destroy empty containers
- if (parent->type == C_CONTAINER) {
+ swayc_t *parent = view->parent;
+ if (parent && parent->type == C_CONTAINER) {
return destroy_container(parent);
}
return parent;
@@ -707,8 +707,10 @@ swayc_t *container_under_pointer(void) {
if (lookup->children && !lookup->unmanaged) {
return NULL;
}
- struct wlc_point origin;
- wlc_pointer_get_position(&origin);
+ double x, y;
+ wlc_pointer_get_position_v2(&x, &y);
+ struct wlc_point origin = { .x = x, .y = y };
+
while (lookup && lookup->type != C_VIEW) {
int i;
int len;
@@ -847,7 +849,6 @@ int swayc_gap(swayc_t *container) {
void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
if (container) {
- f(container, data);
int i;
if (container->children) {
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
container_map(child, f, data);
}
}
+ f(container, data);
}
}
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 @@
enum criteria_type { // *must* keep in sync with criteria_strings[]
CRIT_CLASS,
+ CRIT_CON_ID,
CRIT_CON_MARK,
+ CRIT_FLOATING,
CRIT_ID,
CRIT_INSTANCE,
+ CRIT_TILING,
CRIT_TITLE,
CRIT_URGENT,
CRIT_WINDOW_ROLE,
@@ -25,9 +28,12 @@ enum criteria_type { // *must* keep in sync with criteria_strings[]
static const char * const criteria_strings[CRIT_LAST] = {
[CRIT_CLASS] = "class",
+ [CRIT_CON_ID] = "con_id",
[CRIT_CON_MARK] = "con_mark",
+ [CRIT_FLOATING] = "floating",
[CRIT_ID] = "id",
[CRIT_INSTANCE] = "instance",
+ [CRIT_TILING] = "tiling",
[CRIT_TITLE] = "title",
[CRIT_URGENT] = "urgent", // either "latest" or "oldest" ...
[CRIT_WINDOW_ROLE] = "window_role",
@@ -108,6 +114,7 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str
char **argv = *buf = calloc(max_tokens, sizeof(char*));
argv[0] = base; // this needs to be freed by caller
+ bool quoted = true;
*argc = 1; // uneven = name, even = value
while (*head && *argc < max_tokens) {
@@ -128,7 +135,8 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str
if (*(namep) == ' ') {
namep = strrchr(namep, ' ') + 1;
}
- argv[(*argc)++] = namep;
+ argv[*argc] = namep;
+ *argc += 1;
}
} else if (*head == '"') {
if (*argc % 2 != 0) {
@@ -137,21 +145,38 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str
"Found quoted value where it was not expected");
} else if (!valp) { // value starts here
valp = head + 1;
+ quoted = true;
} else {
// value ends here
- argv[(*argc)++] = valp;
+ argv[*argc] = valp;
+ *argc += 1;
*head = '\0';
valp = NULL;
namep = head + 1;
}
- } else if (*argc % 2 == 0 && !valp && *head != ' ') {
- // We're expecting a quoted value, haven't found one yet, and this
- // is not an empty space.
- return strdup("Unable to parse criteria: "
- "Names must be unquoted, values must be quoted");
+ } else if (*argc % 2 == 0 && *head != ' ') {
+ // parse unquoted values
+ if (!valp) {
+ quoted = false;
+ valp = head; // value starts here
+ }
+ } else if (valp && !quoted && *head == ' ') {
+ // value ends here
+ argv[*argc] = valp;
+ *argc += 1;
+ *head = '\0';
+ valp = NULL;
+ namep = head + 1;
}
head++;
}
+
+ // catch last unquoted value if needed
+ if (valp && !quoted && !*head) {
+ argv[*argc] = valp;
+ *argc += 1;
+ }
+
return NULL;
}
@@ -263,6 +288,15 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
matches++;
}
break;
+ case CRIT_CON_ID: {
+ char *endptr;
+ size_t crit_id = strtoul(crit->raw, &endptr, 10);
+
+ if (*endptr == 0 && cont->id == crit_id) {
+ ++matches;
+ }
+ break;
+ }
case CRIT_CON_MARK:
if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) {
// Make sure it isn't matching the NUL string
@@ -271,6 +305,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
}
}
break;
+ case CRIT_FLOATING:
+ if (cont->is_floating) {
+ matches++;
+ }
+ break;
case CRIT_ID:
if (!cont->app_id) {
// ignore
@@ -290,6 +329,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
matches++;
}
break;
+ case CRIT_TILING:
+ if (!cont->is_floating) {
+ matches++;
+ }
+ break;
case CRIT_TITLE:
if (!cont->name) {
// 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) {
wlc_view_focus(handle);
wlc_view_bring_to_front(handle);
newview = new_floating_view(handle);
+ /* fallthrough */
case WLC_BIT_POPUP:
wlc_view_bring_to_front(handle);
break;
@@ -552,21 +553,24 @@ static void handle_view_destroyed(wlc_handle handle) {
bool fullscreen = swayc_is_fullscreen(view);
remove_view_from_scratchpad(view);
swayc_t *parent = destroy_view(view);
- if (fullscreen) {
- parent->fullscreen = NULL;
- }
+ if (parent) {
+ if (fullscreen) {
+ parent->fullscreen = NULL;
+ }
- // Destroy empty workspaces
- if (parent->type == C_WORKSPACE &&
- parent->children->length == 0 &&
- parent->floating->length == 0 &&
- swayc_active_workspace() != parent &&
- !parent->visible) {
- parent = destroy_workspace(parent);
- }
+ ipc_event_window(parent, "close");
- arrange_windows(parent, -1, -1);
- ipc_event_window(parent, "close");
+ // Destroy empty workspaces
+ if (parent->type == C_WORKSPACE &&
+ parent->children->length == 0 &&
+ parent->floating->length == 0 &&
+ swayc_active_workspace() != parent &&
+ !parent->visible) {
+ parent = destroy_workspace(parent);
+ }
+
+ arrange_windows(parent, -1, -1);
+ }
} else {
// Is it unmanaged?
int i;
@@ -582,6 +586,15 @@ static void handle_view_destroyed(wlc_handle handle) {
}
}
}
+ // Is it in the scratchpad?
+ for (i = 0; i < scratchpad->length; ++i) {
+ swayc_t *item = scratchpad->items[i];
+ if (item->handle == handle) {
+ list_del(scratchpad, i);
+ destroy_view(item);
+ break;
+ }
+ }
}
set_focused_container(get_focused_view(&root_container));
}
@@ -805,11 +818,11 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
struct sway_binding *binding = mode->bindings->items[i];
if ((modifiers->mods ^ binding->modifiers) == 0) {
switch (state) {
- case WLC_KEY_STATE_PRESSED: {
+ case WLC_KEY_STATE_PRESSED:
if (!binding->release && valid_bindsym(binding)) {
list_add(candidates, binding);
}
- }
+ break;
case WLC_KEY_STATE_RELEASED:
if (binding->release && handle_bindsym_release(binding)) {
list_free(candidates);
@@ -842,12 +855,13 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
return EVENT_PASSTHROUGH;
}
-static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_point *origin) {
+static bool handle_pointer_motion(wlc_handle handle, uint32_t time, double x, double y) {
if (desktop_shell.is_locked) {
return EVENT_PASSTHROUGH;
}
- struct wlc_point new_origin = *origin;
+ double new_x = x;
+ double new_y = y;
// Switch to adjacent output if touching output edge.
//
// 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
!pointer_state.left.held && !pointer_state.right.held && !pointer_state.scroll.held) {
swayc_t *output = swayc_active_output(), *adjacent = NULL;
- struct wlc_point abs_pos = *origin;
- abs_pos.x += output->x;
- abs_pos.y += output->y;
- if (origin->x == 0) { // Left edge
+ struct wlc_point abs_pos = { .x = x + output->x, .y = y + output->y };
+ if (x <= 0) { // Left edge
if ((adjacent = swayc_adjacent_output(output, MOVE_LEFT, &abs_pos, false))) {
if (workspace_switch(swayc_active_workspace_for(adjacent))) {
- new_origin.x = adjacent->width;
+ new_x = adjacent->width;
// adjust for differently aligned outputs (well, this is
// only correct when the two outputs have the same
// resolution or the same dpi I guess, it should take
// physical attributes into account)
- new_origin.y += (output->y - adjacent->y);
+ new_y += (output->y - adjacent->y);
}
}
- } else if ((double)origin->x == output->width) { // Right edge
+ } else if (x >= output->width) { // Right edge
if ((adjacent = swayc_adjacent_output(output, MOVE_RIGHT, &abs_pos, false))) {
if (workspace_switch(swayc_active_workspace_for(adjacent))) {
- new_origin.x = 0;
- new_origin.y += (output->y - adjacent->y);
+ new_x = 0;
+ new_y += (output->y - adjacent->y);
}
}
- } else if (origin->y == 0) { // Top edge
+ } else if (y <= 0) { // Top edge
if ((adjacent = swayc_adjacent_output(output, MOVE_UP, &abs_pos, false))) {
if (workspace_switch(swayc_active_workspace_for(adjacent))) {
- new_origin.y = adjacent->height;
- new_origin.x += (output->x - adjacent->x);
+ new_y = adjacent->height;
+ new_x += (output->x - adjacent->x);
}
}
- } else if ((double)origin->y == output->height) { // Bottom edge
+ } else if (y >= output->height) { // Bottom edge
if ((adjacent = swayc_adjacent_output(output, MOVE_DOWN, &abs_pos, false))) {
if (workspace_switch(swayc_active_workspace_for(adjacent))) {
- new_origin.y = 0;
- new_origin.x += (output->x - adjacent->x);
+ new_y = 0;
+ new_x += (output->x - adjacent->x);
}
}
}
}
- pointer_position_set(&new_origin, false);
+ pointer_position_set(new_x, new_y, false);
swayc_t *focused = get_focused_container(&root_container);
if (focused->type == C_VIEW) {
@@ -935,15 +947,15 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
struct sway_binding *binding = mode->bindings->items[i];
if ((modifiers->mods ^ binding->modifiers) == 0) {
switch (state) {
- case WLC_BUTTON_STATE_PRESSED: {
- if (!binding->release && handle_bindsym(binding, button, 0)) {
- return EVENT_HANDLED;
- }
+ case WLC_BUTTON_STATE_PRESSED:
+ if (!binding->release && handle_bindsym(binding, button, 0)) {
+ return EVENT_HANDLED;
+ }
+ break;
+ case WLC_BUTTON_STATE_RELEASED:
+ if (binding->release && handle_bindsym(binding, button, 0)) {
+ return EVENT_HANDLED;
}
- case WLC_BUTTON_STATE_RELEASED:
- if (binding->release && handle_bindsym(binding, button, 0)) {
- return EVENT_HANDLED;
- }
break;
}
}
@@ -1084,16 +1096,8 @@ bool handle_pointer_scroll(wlc_handle view, uint32_t time, const struct wlc_modi
return EVENT_PASSTHROUGH;
}
-static void clip_test_cb(void *data, const char *type, int fd) {
- const char *str = data;
- write(fd, str, strlen(str));
- close(fd);
-}
-
static void handle_wlc_ready(void) {
sway_log(L_DEBUG, "Compositor is ready, executing cmds in queue");
- const char *type = "text/plain;charset=utf-8";
- wlc_set_selection("test", &type, 1, &clip_test_cb);
// Execute commands until there are none left
config->active = true;
while (config->cmd_queue->length) {
@@ -1122,7 +1126,7 @@ void register_wlc_handlers() {
wlc_set_view_request_state_cb(handle_view_state_request);
wlc_set_view_properties_updated_cb(handle_view_properties_updated);
wlc_set_keyboard_key_cb(handle_key);
- wlc_set_pointer_motion_cb(handle_pointer_motion);
+ wlc_set_pointer_motion_cb_v2(handle_pointer_motion);
wlc_set_pointer_button_cb(handle_pointer_button);
wlc_set_pointer_scroll_cb(handle_pointer_scroll);
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) {
pointer_state.mode = 0;
}
-void pointer_position_set(struct wlc_point *new_origin, bool force_focus) {
- struct wlc_point origin;
- wlc_pointer_get_position(&origin);
- pointer_state.delta.x = new_origin->x - origin.x;
- pointer_state.delta.y = new_origin->y - origin.y;
+void pointer_position_set(double new_x, double new_y, bool force_focus) {
+ double x, y;
+ wlc_pointer_get_position_v2(&x, &y);
+ pointer_state.delta.x = new_x - x;
+ pointer_state.delta.y = new_y - y;
- wlc_pointer_set_position(new_origin);
+ wlc_pointer_set_position_v2(new_x, new_y);
// Update view under pointer
swayc_t *prev_view = pointer_state.view;
@@ -226,10 +226,7 @@ void pointer_position_set(struct wlc_point *new_origin, bool force_focus) {
}
void center_pointer_on(swayc_t *view) {
- struct wlc_point new_origin;
- new_origin.x = view->x + view->width/2;
- new_origin.y = view->y + view->height/2;
- pointer_position_set(&new_origin, true);
+ pointer_position_set(view->x + view->width/2, view->y + view->height/2, true);
}
// Mode set left/right click
@@ -269,10 +266,10 @@ static void pointer_mode_set_resizing(void) {
int midway_x = initial.ptr->x + initial.ptr->width/2;
int midway_y = initial.ptr->y + initial.ptr->height/2;
- struct wlc_point origin;
- wlc_pointer_get_position(&origin);
- lock.left = origin.x > midway_x;
- lock.top = origin.y > midway_y;
+ double x, y;
+ wlc_pointer_get_position_v2(&x, &y);
+ lock.left = x > midway_x;
+ lock.top = y > midway_y;
if (initial.ptr->is_floating) {
pointer_state.mode = M_RESIZING | M_FLOATING;
@@ -346,10 +343,10 @@ void pointer_mode_update(void) {
pointer_state.mode = 0;
return;
}
- struct wlc_point origin;
- wlc_pointer_get_position(&origin);
- int dx = origin.x;
- int dy = origin.y;
+ double x, y;
+ wlc_pointer_get_position_v2(&x, &y);
+ int dx = x;
+ int dy = y;
switch (pointer_state.mode) {
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)
json_object_object_add(object, "num", json_object_new_int(num));
json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL);
- json_object_object_add(object, "urgent", json_object_new_boolean(false));
json_object_object_add(object, "type", json_object_new_string("workspace"));
json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout));
}
@@ -156,38 +155,14 @@ static const char *ipc_json_get_scratchpad_state(swayc_t *c) {
static void ipc_json_describe_view(swayc_t *c, json_object *object) {
json_object *props = json_object_new_object();
- float percent = ipc_json_child_percentage(c);
- const char *layout = (c->parent->type == C_CONTAINER) ?
- ipc_json_layout_description(c->parent->layout) : "none";
- const char *last_layout = (c->parent->type == C_CONTAINER) ?
- ipc_json_layout_description(c->parent->prev_layout) : "none";
- wlc_handle parent = wlc_view_get_parent(c->handle);
-
json_object_object_add(object, "type", json_object_new_string((c->is_floating) ? "floating_con" : "con"));
+ wlc_handle parent = wlc_view_get_parent(c->handle);
json_object_object_add(object, "scratchpad_state",
json_object_new_string(ipc_json_get_scratchpad_state(c)));
- json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL);
- // TODO: make urgency actually work once Sway supports it
- json_object_object_add(object, "urgent", json_object_new_boolean(false));
- json_object_object_add(object, "layout",
- (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout));
- json_object_object_add(object, "last_split_layout",
- (strcmp(last_layout, "null") == 0) ? NULL : json_object_new_string(last_layout));
- json_object_object_add(object, "workspace_layout",
- json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout)));
-
- json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c)));
- json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness));
-
- json_object_object_add(object, "rect", ipc_json_create_rect(c));
- json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry));
- json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry));
- json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry));
json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL);
- json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat
json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) :
c->app_id ? json_object_new_string(c->app_id) : NULL);
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) {
c->is_floating ? "auto_on" : "auto_off")); // we can't state the cause
json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL);
+
+ if (c->parent) {
+ const char *layout = (c->parent->type == C_CONTAINER) ?
+ ipc_json_layout_description(c->parent->layout) : "none";
+ const char *last_layout = (c->parent->type == C_CONTAINER) ?
+ ipc_json_layout_description(c->parent->prev_layout) : "none";
+ json_object_object_add(object, "layout",
+ (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout));
+ json_object_object_add(object, "last_split_layout",
+ (strcmp(last_layout, "null") == 0) ? NULL : json_object_new_string(last_layout));
+ json_object_object_add(object, "workspace_layout",
+ json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout)));
+ }
+}
+
+static void ipc_json_describe_root(swayc_t *c, json_object *object) {
+ json_object_object_add(object, "type", json_object_new_string("root"));
+ json_object_object_add(object, "layout", json_object_new_string("splith"));
}
json_object *ipc_json_describe_container(swayc_t *c) {
+ float percent = ipc_json_child_percentage(c);
+
if (!(sway_assert(c, "Container must not be null."))) {
return NULL;
}
@@ -218,9 +213,19 @@ json_object *ipc_json_describe_container(swayc_t *c) {
json_object_object_add(object, "visible", json_object_new_boolean(c->visible));
json_object_object_add(object, "focused", json_object_new_boolean(c == current_focus));
+ json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c)));
+ json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry));
+ json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry));
+ json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry));
+ json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL);
+ json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat
+ // TODO: make urgency actually work once Sway supports it
+ json_object_object_add(object, "urgent", json_object_new_boolean(false));
+ json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness));
+
switch (c->type) {
case C_ROOT:
- json_object_object_add(object, "type", json_object_new_string("root"));
+ ipc_json_describe_root(c, object);
break;
case C_OUTPUT:
@@ -451,21 +456,50 @@ json_object *ipc_json_describe_container_recursive(swayc_t *c) {
int i;
json_object *floating = json_object_new_array();
- if (c->type != C_VIEW && c->floating && c->floating->length > 0) {
+ if (c->type != C_VIEW && c->floating) {
for (i = 0; i < c->floating->length; ++i) {
- json_object_array_add(floating, ipc_json_describe_container_recursive(c->floating->items[i]));
+ swayc_t *item = c->floating->items[i];
+ json_object_array_add(floating, ipc_json_describe_container_recursive(item));
}
}
json_object_object_add(object, "floating_nodes", floating);
json_object *children = json_object_new_array();
- if (c->type != C_VIEW && c->children && c->children->length > 0) {
+ if (c->type != C_VIEW && c->children) {
for (i = 0; i < c->children->length; ++i) {
json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i]));
}
}
json_object_object_add(object, "nodes", children);
+ json_object *focus = json_object_new_array();
+ if (c->type != C_VIEW) {
+ if (c->focused) {
+ json_object_array_add(focus, json_object_new_double(c->focused->id));
+ }
+ if (c->floating) {
+ for (i = 0; i < c->floating->length; ++i) {
+ swayc_t *item = c->floating->items[i];
+ if (item == c->focused) {
+ continue;
+ }
+
+ json_object_array_add(focus, json_object_new_double(item->id));
+ }
+ }
+ if (c->children) {
+ for (i = 0; i < c->children->length; ++i) {
+ swayc_t *item = c->children->items[i];
+ if (item == c->focused) {
+ continue;
+ }
+
+ json_object_array_add(focus, json_object_new_double(item->id));
+ }
+ }
+ }
+ json_object_object_add(object, "focus", focus);
+
if (c->type == C_ROOT) {
json_object *scratchpad_json = json_object_new_array();
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'};
struct ipc_client {
struct wlc_event_source *event_source;
+ struct wlc_event_source *writable_event_source;
int fd;
uint32_t payload_length;
uint32_t security_policy;
enum ipc_command_type current_command;
enum ipc_command_type subscribed_events;
+ size_t write_buffer_len;
+ size_t write_buffer_size;
+ char *write_buffer;
};
static list_t *ipc_get_pixel_requests = NULL;
@@ -72,6 +76,7 @@ struct get_clipboard_request {
struct sockaddr_un *ipc_user_sockaddr(void);
int ipc_handle_connection(int fd, uint32_t mask, void *data);
int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
+int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data);
void ipc_client_disconnect(struct ipc_client *client);
void ipc_client_handle_command(struct ipc_client *client);
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) {
close(client_fd);
return 0;
}
+ if ((flags = fcntl(client_fd, F_GETFL)) == -1
+ || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) {
+ sway_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket");
+ close(client_fd);
+ return 0;
+ }
struct ipc_client* client = malloc(sizeof(struct ipc_client));
if (!client) {
@@ -193,10 +204,22 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
client->fd = client_fd;
client->subscribed_events = 0;
client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client);
+ client->writable_event_source = NULL;
+
+ client->write_buffer_size = 128;
+ client->write_buffer_len = 0;
+ client->write_buffer = malloc(client->write_buffer_size);
+ if (!client->write_buffer) {
+ sway_log(L_ERROR, "Unable to allocate ipc client write buffer");
+ close(client_fd);
+ return 0;
+ }
pid_t pid = get_client_pid(client->fd);
client->security_policy = get_ipc_policy_mask(pid);
+ sway_log(L_DEBUG, "New client: fd %d, pid %d", client_fd, pid);
+
list_add(ipc_client_list, client);
return 0;
@@ -219,6 +242,8 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
return 0;
}
+ sway_log(L_DEBUG, "Client %d readable", client->fd);
+
int read_available;
if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
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) {
uint8_t buf[ipc_header_size];
uint32_t *buf32 = (uint32_t*)(buf + sizeof(ipc_magic));
+ // Should be fully available, because read_available >= ipc_header_size
ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
if (received == -1) {
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) {
return 0;
}
+int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
+ struct ipc_client *client = data;
+
+ if (mask & WLC_EVENT_ERROR) {
+ sway_log(L_ERROR, "IPC Client socket error, removing client");
+ ipc_client_disconnect(client);
+ return 0;
+ }
+
+ if (mask & WLC_EVENT_HANGUP) {
+ sway_log(L_DEBUG, "Client %d hung up", client->fd);
+ ipc_client_disconnect(client);
+ return 0;
+ }
+
+ if (client->write_buffer_len <= 0) {
+ return 0;
+ }
+
+ sway_log(L_DEBUG, "Client %d writable", client->fd);
+
+ ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
+
+ if (written == -1 && errno == EAGAIN) {
+ return 0;
+ } else if (written == -1) {
+ sway_log_errno(L_INFO, "Unable to send data from queue to IPC client");
+ ipc_client_disconnect(client);
+ return 0;
+ }
+
+ memmove(client->write_buffer, client->write_buffer + written, client->write_buffer_len - written);
+ client->write_buffer_len -= written;
+
+ if (client->write_buffer_len == 0 && client->writable_event_source) {
+ wlc_event_source_remove(client->writable_event_source);
+ client->writable_event_source = NULL;
+ }
+
+ return 0;
+}
+
void ipc_client_disconnect(struct ipc_client *client) {
if (!sway_assert(client != NULL, "client != NULL")) {
return;
@@ -274,9 +342,13 @@ void ipc_client_disconnect(struct ipc_client *client) {
sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
wlc_event_source_remove(client->event_source);
+ if (client->writable_event_source) {
+ wlc_event_source_remove(client->writable_event_source);
+ }
int i = 0;
while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++;
list_del(ipc_client_list, i);
+ free(client->write_buffer);
close(client->fd);
free(client);
}
@@ -608,6 +680,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
return;
}
if (client->payload_length > 0) {
+ // Payload should be fully available
ssize_t received = recv(client->fd, buf, client->payload_length, 0);
if (received == -1)
{
@@ -874,17 +947,36 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
data32[0] = payload_length;
data32[1] = client->current_command;
- if (write(client->fd, data, ipc_header_size) == -1) {
- sway_log_errno(L_INFO, "Unable to send header to IPC client");
+ while (client->write_buffer_len + ipc_header_size + payload_length >=
+ client->write_buffer_size) {
+ client->write_buffer_size *= 2;
+ }
+
+ // TODO: reduce the limit back to 4 MB when screenshooter is implemented
+ if (client->write_buffer_size > (1 << 28)) { // 256 MB
+ sway_log(L_ERROR, "Client write buffer too big, disconnecting client");
+ ipc_client_disconnect(client);
return false;
}
- if (write(client->fd, payload, payload_length) == -1) {
- sway_log_errno(L_INFO, "Unable to send payload to IPC client");
+ char *new_buffer = realloc(client->write_buffer, client->write_buffer_size);
+ if (!new_buffer) {
+ sway_log(L_ERROR, "Unable to reallocate ipc client write buffer");
+ ipc_client_disconnect(client);
return false;
}
+ client->write_buffer = new_buffer;
+
+ memcpy(client->write_buffer + client->write_buffer_len, data, ipc_header_size);
+ client->write_buffer_len += ipc_header_size;
+ memcpy(client->write_buffer + client->write_buffer_len, payload, payload_length);
+ client->write_buffer_len += payload_length;
+
+ if (!client->writable_event_source) {
+ client->writable_event_source = wlc_event_loop_add_fd(client->fd, WLC_EVENT_WRITABLE, ipc_client_handle_writable, client);
+ }
- sway_log(L_DEBUG, "Send IPC reply: %s", payload);
+ sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
return true;
}
@@ -984,11 +1076,7 @@ void ipc_event_window(swayc_t *window, const char *change) {
sway_log(L_DEBUG, "Sending window::%s event", change);
json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string(change));
- if (strcmp(change, "close") == 0 || !window) {
- json_object_object_add(obj, "container", NULL);
- } else {
- json_object_object_add(obj, "container", ipc_json_describe_container(window));
- }
+ json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window));
const char *json_string = json_object_to_json_string(obj);
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) {
}
}
+void detect_raspi() {
+ bool raspi = false;
+ FILE *f = fopen("/sys/firmware/devicetree/base/model", "r");
+ if (!f) {
+ return;
+ }
+ char *line;
+ while(!feof(f)) {
+ if (!(line = read_line(f))) {
+ break;
+ }
+ if (strstr(line, "Raspberry Pi")) {
+ raspi = true;
+ }
+ free(line);
+ }
+ fclose(f);
+ FILE *g = fopen("/proc/modules", "r");
+ if (!g) {
+ return;
+ }
+ bool vc4 = false;
+ while (!feof(g)) {
+ if (!(line = read_line(g))) {
+ break;
+ }
+ if (strstr(line, "vc4")) {
+ vc4 = true;
+ }
+ free(line);
+ }
+ fclose(g);
+ if (!vc4 && raspi) {
+ fprintf(stderr, "\x1B[1;31mWarning: You have a "
+ "Raspberry Pi, but the vc4 Module is "
+ "not loaded! Set 'dtoverlay=vc4-kms-v3d'"
+ "in /boot/config.txt and reboot.\x1B[0m\n");
+ }
+}
+
void detect_proprietary() {
FILE *f = fopen("/proc/modules", "r");
if (!f) {
@@ -366,6 +406,7 @@ int main(int argc, char **argv) {
log_distro();
log_env();
detect_proprietary();
+ detect_raspi();
input_devices = create_list();
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
-------
Maintained by Drew DeVault <sir@cmpwn.com>, who is assisted by other open
source contributors. For more information about sway development, see
-<https://github.com/SirCmpwn/sway>.
+<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
Maintained by Drew DeVault <sir@cmpwn.com>, who is assisted by other open
source contributors. For more information about sway development, see
-<https://github.com/SirCmpwn/sway>.
+<https://github.com/swaywm/sway>.
See Also
--------
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) {
// workspace n
char *cmd = argsep(&cmdlist, " ");
if (cmdlist) {
- name = argsep(&cmdlist, " ,;");
+ name = argsep(&cmdlist, ",;");
}
if (strcmp("workspace", cmd) == 0 && name) {