aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/pool-buffer.c2
-rw-r--r--include/sway/config.h1
-rw-r--r--include/sway/input/seat.h3
-rw-r--r--include/sway/output.h2
-rw-r--r--include/sway/tree/container.h5
-rw-r--r--include/sway/tree/layout.h12
-rw-r--r--sway/commands.c3
-rw-r--r--sway/commands/focus.c7
-rw-r--r--sway/commands/focus_follows_mouse.c12
-rw-r--r--sway/commands/mouse_warping.c19
-rw-r--r--sway/commands/move.c184
-rw-r--r--sway/config.c1
-rw-r--r--sway/desktop/layer_shell.c5
-rw-r--r--sway/desktop/output.c34
-rw-r--r--sway/desktop/xwayland.c18
-rw-r--r--sway/input/cursor.c70
-rw-r--r--sway/input/keyboard.c4
-rw-r--r--sway/input/seat.c36
-rw-r--r--sway/meson.build3
-rw-r--r--sway/server.c15
-rw-r--r--sway/tree/container.c18
-rw-r--r--sway/tree/layout.c58
-rw-r--r--sway/tree/output.c11
23 files changed, 430 insertions, 93 deletions
diff --git a/client/pool-buffer.c b/client/pool-buffer.c
index 93cfcfc5..b5ed9c98 100644
--- a/client/pool-buffer.c
+++ b/client/pool-buffer.c
@@ -57,7 +57,7 @@ static struct pool_buffer *create_buffer(struct wl_shm *shm,
char *name;
int fd = create_pool_file(size, &name);
- assert(fd);
+ assert(fd != -1);
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
buf->buffer = wl_shm_pool_create_buffer(pool, 0,
diff --git a/include/sway/config.h b/include/sway/config.h
index ac1105b4..03b51948 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -304,7 +304,6 @@ struct sway_config {
bool reloading;
bool reading;
bool auto_back_and_forth;
- bool seamless_mouse;
bool show_marks;
bool edge_gaps;
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 496bfd5d..31210a5a 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -56,6 +56,9 @@ void sway_seat_configure_xcursor(struct sway_seat *seat);
void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *container);
+void sway_seat_set_focus_warp(struct sway_seat *seat,
+ struct sway_container *container, bool warp);
+
struct sway_container *sway_seat_get_focus(struct sway_seat *seat);
/**
diff --git a/include/sway/output.h b/include/sway/output.h
index b4980cd8..b343ecff 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -36,4 +36,6 @@ void output_damage_whole(struct sway_output *output);
void output_damage_whole_view(struct sway_output *output,
struct sway_view *view);
+struct sway_container *output_by_name(const char *name);
+
#endif
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 6aa66da0..aff2e58e 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -84,9 +84,14 @@ struct sway_container {
struct {
struct wl_signal destroy;
+ // Raised after the tree updates, but before arrange_windows
+ // Passed the previous parent
+ struct wl_signal reparent;
} events;
};
+const char *container_type_to_str(enum sway_container_type type);
+
// TODO only one container create function and pass the type?
struct sway_container *container_output_create(
struct sway_output *sway_output);
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h
index 0a904c4b..e1034657 100644
--- a/include/sway/tree/layout.h
+++ b/include/sway/tree/layout.h
@@ -11,9 +11,6 @@ enum movement_direction {
MOVE_DOWN,
MOVE_PARENT,
MOVE_CHILD,
- MOVE_NEXT,
- MOVE_PREV,
- MOVE_FIRST
};
struct sway_container;
@@ -32,7 +29,8 @@ struct sway_root {
void layout_init(void);
-void container_add_child(struct sway_container *parent, struct sway_container *child);
+void container_add_child(struct sway_container *parent,
+ struct sway_container *child);
struct sway_container *container_add_sibling(struct sway_container *parent,
struct sway_container *child);
@@ -44,7 +42,11 @@ struct sway_container *container_reap_empty(struct sway_container *container);
void container_move_to(struct sway_container* container,
struct sway_container* destination);
-enum sway_container_layout container_get_default_layout(struct sway_container *output);
+void container_move(struct sway_container *container,
+ enum movement_direction dir, int move_amt);
+
+enum sway_container_layout container_get_default_layout(
+ struct sway_container *output);
void container_sort_workspaces(struct sway_container *output);
diff --git a/sway/commands.c b/sway/commands.c
index eee7f254..b6af3d1a 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -98,9 +98,11 @@ static struct cmd_handler handlers[] = {
{ "bindsym", cmd_bindsym },
{ "exec", cmd_exec },
{ "exec_always", cmd_exec_always },
+ { "focus_follows_mouse", cmd_focus_follows_mouse },
{ "include", cmd_include },
{ "input", cmd_input },
{ "mode", cmd_mode },
+ { "mouse_warping", cmd_mouse_warping },
{ "output", cmd_output },
{ "seat", cmd_seat },
{ "workspace", cmd_workspace },
@@ -160,6 +162,7 @@ static struct cmd_handler command_handlers[] = {
{ "focus", cmd_focus },
{ "kill", cmd_kill },
{ "layout", cmd_layout },
+ { "move", cmd_move },
{ "reload", cmd_reload },
};
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 64f079f4..0a521b9e 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -20,10 +20,6 @@ static bool parse_movement_direction(const char *name,
*out = MOVE_PARENT;
} else if (strcasecmp(name, "child") == 0) {
*out = MOVE_CHILD;
- } else if (strcasecmp(name, "next") == 0) {
- *out = MOVE_NEXT;
- } else if (strcasecmp(name, "prev") == 0) {
- *out = MOVE_PREV;
} else {
return false;
}
@@ -51,7 +47,8 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
"Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'");
}
- struct sway_container *next_focus = container_get_in_direction(con, seat, direction);
+ struct sway_container *next_focus = container_get_in_direction(
+ con, seat, direction);
if (next_focus) {
sway_seat_set_focus(seat, next_focus);
}
diff --git a/sway/commands/focus_follows_mouse.c b/sway/commands/focus_follows_mouse.c
new file mode 100644
index 00000000..661e7852
--- /dev/null
+++ b/sway/commands/focus_follows_mouse.c
@@ -0,0 +1,12 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+
+struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ config->focus_follows_mouse = !strcasecmp(argv[0], "yes");
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/mouse_warping.c b/sway/commands/mouse_warping.c
new file mode 100644
index 00000000..eef32ce7
--- /dev/null
+++ b/sway/commands/mouse_warping.c
@@ -0,0 +1,19 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+
+struct cmd_results *cmd_mouse_warping(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "mouse_warping", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ } else if (strcasecmp(argv[0], "output") == 0) {
+ config->mouse_warping = true;
+ } else if (strcasecmp(argv[0], "none") == 0) {
+ config->mouse_warping = false;
+ } else {
+ return cmd_results_new(CMD_FAILURE, "mouse_warping",
+ "Expected 'mouse_warping output|none'");
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
diff --git a/sway/commands/move.c b/sway/commands/move.c
new file mode 100644
index 00000000..ab959b77
--- /dev/null
+++ b/sway/commands/move.c
@@ -0,0 +1,184 @@
+#include <string.h>
+#include <strings.h>
+#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_output_layout.h>
+#include <wlr/util/log.h>
+#include "sway/commands.h"
+#include "sway/input/seat.h"
+#include "sway/output.h"
+#include "sway/tree/container.h"
+#include "sway/tree/layout.h"
+#include "sway/tree/workspace.h"
+#include "stringop.h"
+#include "list.h"
+
+static const char* expected_syntax =
+ "Expected 'move <left|right|up|down> <[px] px>' or "
+ "'move <container|window> to workspace <name>' or "
+ "'move <container|window|workspace> to output <name|direction>' or "
+ "'move position mouse'";
+
+static struct sway_container *output_in_direction(const char *direction,
+ struct wlr_output *reference, int ref_ox, int ref_oy) {
+ int ref_lx = ref_ox + reference->lx,
+ ref_ly = ref_oy + reference->ly;
+ struct {
+ char *name;
+ enum wlr_direction direction;
+ } names[] = {
+ { "up", WLR_DIRECTION_UP },
+ { "down", WLR_DIRECTION_DOWN },
+ { "left", WLR_DIRECTION_LEFT },
+ { "right", WLR_DIRECTION_RIGHT },
+ };
+ for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) {
+ if (strcasecmp(names[i].name, direction) == 0) {
+ struct wlr_output *adjacent = wlr_output_layout_adjacent_output(
+ root_container.sway_root->output_layout,
+ names[i].direction, reference, ref_lx, ref_ly);
+ if (adjacent) {
+ struct sway_output *sway_output = adjacent->data;
+ return sway_output->swayc;
+ }
+ break;
+ }
+ }
+ return output_by_name(direction);
+}
+
+static struct cmd_results *cmd_move_container(struct sway_container *current,
+ int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "move container/window",
+ EXPECTED_AT_LEAST, 4))) {
+ return error;
+ } else if (strcasecmp(argv[1], "to") == 0
+ && strcasecmp(argv[2], "workspace") == 0) {
+ // move container to workspace x
+ if (current->type == C_WORKSPACE) {
+ // TODO: Wrap children in a container and move that
+ return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
+ } else if (current->type != C_CONTAINER && current->type != C_VIEW) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Can only move containers and views.");
+ }
+ struct sway_container *ws;
+ const char *num_name = NULL;
+ char *ws_name = NULL;
+ if (argc == 5 && strcasecmp(argv[3], "number") == 0) {
+ // move "container to workspace number x"
+ 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) {
+ ws = workspace_create(ws_name ? ws_name : num_name);
+ }
+ free(ws_name);
+ struct sway_container *old_parent = current->parent;
+ struct sway_container *focus = sway_seat_get_focus_inactive(
+ config->handler_context.seat, ws);
+ container_move_to(current, focus);
+ sway_seat_set_focus(config->handler_context.seat, old_parent);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ } else if (strcasecmp(argv[1], "to") == 0
+ && strcasecmp(argv[2], "output") == 0) {
+ if (current->type == C_WORKSPACE) {
+ // TODO: Wrap children in a container and move that
+ return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
+ } else if (current->type != C_CONTAINER
+ && current->type != C_VIEW) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Can only move containers and views.");
+ }
+ struct sway_container *source = container_parent(current, C_OUTPUT);
+ struct sway_container *destination = output_in_direction(argv[3],
+ source->sway_output->wlr_output, current->x, current->y);
+ if (!destination) {
+ return cmd_results_new(CMD_FAILURE, "move workspace",
+ "Can't find output with name/direction '%s'", argv[3]);
+ }
+ struct sway_container *focus = sway_seat_get_focus_inactive(
+ config->handler_context.seat, destination);
+ if (!focus) {
+ // We've never been to this output before
+ focus = destination->children->items[0];
+ }
+ struct sway_container *old_parent = current->parent;
+ container_move_to(current, focus);
+ sway_seat_set_focus(config->handler_context.seat, old_parent);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
+ return cmd_results_new(CMD_INVALID, "move", expected_syntax);
+}
+
+static struct cmd_results *cmd_move_workspace(struct sway_container *current,
+ int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) {
+ return error;
+ } else if (strcasecmp(argv[1], "to") != 0
+ || strcasecmp(argv[2], "output") != 0) {
+ return cmd_results_new(CMD_INVALID, "move", expected_syntax);
+ }
+ struct sway_container *source = container_parent(current, C_OUTPUT);
+ int center_x = current->width / 2 + current->x,
+ center_y = current->height / 2 + current->y;
+ struct sway_container *destination = output_in_direction(argv[3],
+ source->sway_output->wlr_output, center_x, center_y);
+ if (!destination) {
+ return cmd_results_new(CMD_FAILURE, "move workspace",
+ "Can't find output with name/direction '%s'", argv[3]);
+ }
+ if (current->type != C_WORKSPACE) {
+ current = container_parent(current, C_WORKSPACE);
+ }
+ container_move_to(current, destination);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+struct cmd_results *cmd_move(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ int move_amt = 10;
+ if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ struct sway_container *current = config->handler_context.current_container;
+
+ if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) {
+ char *inv;
+ move_amt = (int)strtol(argv[1], &inv, 10);
+ if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Invalid distance specified");
+ }
+ }
+
+ if (strcasecmp(argv[0], "left") == 0) {
+ container_move(current, MOVE_LEFT, move_amt);
+ } else if (strcasecmp(argv[0], "right") == 0) {
+ container_move(current, MOVE_RIGHT, move_amt);
+ } else if (strcasecmp(argv[0], "up") == 0) {
+ container_move(current, MOVE_UP, move_amt);
+ } else if (strcasecmp(argv[0], "down") == 0) {
+ container_move(current, MOVE_DOWN, move_amt);
+ } else if (strcasecmp(argv[0], "container") == 0
+ || strcasecmp(argv[0], "window") == 0) {
+ return cmd_move_container(current, argc, argv);
+ } else if (strcasecmp(argv[0], "workspace") == 0) {
+ return cmd_move_workspace(current, argc, argv);
+ } else if (strcasecmp(argv[0], "scratchpad") == 0
+ || (strcasecmp(argv[0], "to") == 0
+ && strcasecmp(argv[1], "scratchpad") == 0)) {
+ // TODO: scratchpad
+ return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
+ } else if (strcasecmp(argv[0], "position") == 0) {
+ // TODO: floating
+ return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
+ } else {
+ return cmd_results_new(CMD_INVALID, "move", expected_syntax);
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/config.c b/sway/config.c
index e9e7057d..0eecf7f6 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -178,7 +178,6 @@ static void config_defaults(struct sway_config *config) {
config->active = false;
config->failed = false;
config->auto_back_and_forth = false;
- config->seamless_mouse = true;
config->reading = false;
config->show_marks = true;
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 5c96659a..c18f51c7 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -238,11 +238,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&sway_layer->unmap.link);
wl_list_remove(&sway_layer->surface_commit.link);
if (sway_layer->layer_surface->output != NULL) {
+ struct sway_output *output = sway_layer->layer_surface->output->data;
+ arrange_layers(output);
+
wl_list_remove(&sway_layer->output_destroy.link);
}
- struct sway_output *output = sway_layer->layer_surface->output->data;
free(sway_layer);
- arrange_layers(output);
}
static void handle_map(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index c248b29e..c4265818 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -229,9 +229,12 @@ static void render_output(struct sway_output *output, struct timespec *when,
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus =
sway_seat_get_focus_inactive(seat, output->swayc);
- struct sway_container *workspace = (focus->type == C_WORKSPACE ?
- focus :
- container_parent(focus, C_WORKSPACE));
+ if (!focus) {
+ // We've never been to this output before
+ focus = output->swayc->children->items[0];
+ }
+ struct sway_container *workspace = focus->type == C_WORKSPACE ?
+ focus : container_parent(focus, C_WORKSPACE);
struct render_data rdata = {
.output = output,
@@ -243,14 +246,25 @@ static void render_output(struct sway_output *output, struct timespec *when,
struct sway_view *view;
wl_list_for_each(view, &root_container.sway_root->unmanaged_views,
unmanaged_view_link) {
- if (view->type == SWAY_XWAYLAND_VIEW) {
- // the only kind of unamanged view right now is xwayland override
- // redirect
- int view_x = view->wlr_xwayland_surface->x;
- int view_y = view->wlr_xwayland_surface->y;
- render_surface(view->surface, wlr_output, &output->last_frame,
- view_x, view_y, 0);
+ if (view->type != SWAY_XWAYLAND_VIEW) {
+ continue;
+ }
+
+ struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
+
+ const struct wlr_box view_box = {
+ .x = xsurface->x,
+ .y = xsurface->y,
+ .width = xsurface->width,
+ .height = xsurface->height,
+ };
+ struct wlr_box intersection;
+ if (!wlr_box_intersection(&view_box, output_box, &intersection)) {
+ continue;
}
+
+ render_surface(view->surface, wlr_output, &output->last_frame,
+ view_box.x - output_box->x, view_box.y - output_box->y, 0);
}
// TODO: Consider revising this when fullscreen windows are supported
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 01c993b3..273ca2bf 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -41,7 +41,7 @@ static void set_size(struct sway_view *view, int width, int height) {
view->sway_xwayland_surface->pending_height = height;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
- wlr_xwayland_surface_configure(xsurface, view->swayc->x, view->swayc->y,
+ wlr_xwayland_surface_configure(xsurface, xsurface->x, xsurface->y,
width, height);
}
@@ -67,13 +67,10 @@ static void set_position(struct sway_view *view, double ox, double oy) {
view->swayc->x = ox;
view->swayc->y = oy;
- if (view->width == 0 || view->height == 0) {
- return;
- }
-
wlr_xwayland_surface_configure(view->wlr_xwayland_surface,
ox + loutput->x, oy + loutput->y,
- view->width, view->height);
+ view->wlr_xwayland_surface->width,
+ view->wlr_xwayland_surface->height);
}
static void set_activated(struct sway_view *view, bool activated) {
@@ -143,8 +140,11 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct sway_view *view = sway_surface->view;
container_view_destroy(view->swayc);
+ wlr_xwayland_surface_set_maximized(xsurface, true);
+
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container);
+ struct sway_container *focus = sway_seat_get_focus_inactive(seat,
+ &root_container);
struct sway_container *cont = container_view_create(focus, view);
view->swayc = cont;
arrange_windows(cont->parent, -1, -1);
@@ -154,7 +154,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
view_damage_whole(sway_surface->view);
}
-static void handle_configure_request(struct wl_listener *listener, void *data) {
+static void handle_request_configure(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, request_configure);
struct wlr_xwayland_surface_configure_event *ev = data;
@@ -209,7 +209,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
wl_signal_add(&xsurface->events.request_configure,
&sway_surface->request_configure);
- sway_surface->request_configure.notify = handle_configure_request;
+ sway_surface->request_configure.notify = handle_request_configure;
wl_signal_add(&xsurface->events.unmap, &sway_surface->unmap);
sway_surface->unmap.notify = handle_unmap;
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 7390816f..d608a9cf 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -50,21 +50,23 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor,
struct wl_list *unmanaged = &root_container.sway_root->unmanaged_views;
struct sway_view *view;
wl_list_for_each_reverse(view, unmanaged, unmanaged_view_link) {
- if (view->type == SWAY_XWAYLAND_VIEW) {
- struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
- struct wlr_box box = {
- .x = xsurface->x,
- .y = xsurface->y,
- .width = xsurface->width,
- .height = xsurface->height,
- };
-
- if (wlr_box_contains_point(&box, cursor->x, cursor->y)) {
- *surface = xsurface->surface;
- *sx = cursor->x - box.x;
- *sy = cursor->y - box.y;
- return view->swayc;
- }
+ if (view->type != SWAY_XWAYLAND_VIEW) {
+ continue;
+ }
+
+ struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
+ struct wlr_box box = {
+ .x = xsurface->x,
+ .y = xsurface->y,
+ .width = xsurface->width,
+ .height = xsurface->height,
+ };
+
+ if (wlr_box_contains_point(&box, cursor->x, cursor->y)) {
+ *surface = xsurface->surface;
+ *sx = cursor->x - box.x;
+ *sy = cursor->y - box.y;
+ return NULL;
}
}
@@ -125,7 +127,10 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,
struct wlr_seat *seat = cursor->seat->wlr_seat;
struct wlr_surface *surface = NULL;
double sx, sy;
- container_at_cursor(cursor, &surface, &sx, &sy);
+ struct sway_container *c = container_at_cursor(cursor, &surface, &sx, &sy);
+ if (c && config->focus_follows_mouse) {
+ sway_seat_set_focus_warp(cursor->seat, c, false);
+ }
// reset cursor if switching between clients
struct wl_client *client = NULL;
@@ -156,8 +161,8 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
cursor_send_pointer_motion(cursor, event->time_msec);
}
-static void handle_cursor_motion_absolute(struct wl_listener *listener,
- void *data) {
+static void handle_cursor_motion_absolute(
+ struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, motion_absolute);
struct wlr_event_pointer_motion_absolute *event = data;
@@ -170,11 +175,30 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
struct wlr_event_pointer_button *event = data;
- if (event->button == BTN_LEFT) {
- struct wlr_surface *surface = NULL;
- double sx, sy;
- struct sway_container *cont =
- container_at_cursor(cursor, &surface, &sx, &sy);
+ struct wlr_surface *surface = NULL;
+ double sx, sy;
+ struct sway_container *cont =
+ container_at_cursor(cursor, &surface, &sx, &sy);
+ // Avoid moving keyboard focus from a surface that accepts it to one
+ // that does not unless the change would move us to a new workspace.
+ //
+ // This prevents, for example, losing focus when clicking on swaybar.
+ //
+ // TODO: Replace this condition with something like
+ // !surface_accepts_keyboard_input
+ if (surface && cont && cont->type != C_VIEW) {
+ struct sway_container *new_ws = cont;
+ if (new_ws && new_ws->type != C_WORKSPACE) {
+ new_ws = container_parent(new_ws, C_WORKSPACE);
+ }
+ struct sway_container *old_ws = sway_seat_get_focus(cursor->seat);
+ if (old_ws && old_ws->type != C_WORKSPACE) {
+ old_ws = container_parent(old_ws, C_WORKSPACE);
+ }
+ if (new_ws != old_ws) {
+ sway_seat_set_focus(cursor->seat, cont);
+ }
+ } else {
sway_seat_set_focus(cursor->seat, cont);
}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 99685052..8d22b684 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -97,8 +97,8 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard,
config->handler_context.seat = keyboard->seat_device->sway_seat;
struct cmd_results *results = execute_command(binding->command, NULL);
if (results->status != CMD_SUCCESS) {
- wlr_log(L_DEBUG, "could not run command for binding: %s",
- binding->command);
+ wlr_log(L_DEBUG, "could not run command for binding: %s (%s)",
+ binding->command, results->error);
}
free_cmd_results(results);
}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index f969636a..9aa34aca 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -1,5 +1,6 @@
#define _XOPEN_SOURCE 700
#include <wlr/types/wlr_cursor.h>
+#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include "sway/tree/container.h"
#include "sway/input/seat.h"
@@ -291,7 +292,8 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) {
seat->cursor->cursor->y);
}
-void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *container) {
+void sway_seat_set_focus_warp(struct sway_seat *seat,
+ struct sway_container *container, bool warp) {
struct sway_container *last_focus = sway_seat_get_focus(seat);
if (container && last_focus == container) {
@@ -311,6 +313,11 @@ void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *containe
if (container->type == C_VIEW) {
struct sway_view *view = container->sway_view;
view_set_activated(view, true);
+ if (view->type == SWAY_XWAYLAND_VIEW) {
+ struct wlr_xwayland *xwayland =
+ seat->input->server->xwayland;
+ wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
+ }
struct wlr_keyboard *keyboard =
wlr_seat_get_keyboard(seat->wlr_seat);
if (keyboard) {
@@ -327,15 +334,33 @@ void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *containe
if (last_focus) {
struct sway_container *last_ws = last_focus;
if (last_ws && last_ws->type != C_WORKSPACE) {
- last_ws = container_parent(last_focus, C_WORKSPACE);
+ last_ws = container_parent(last_ws, C_WORKSPACE);
}
if (last_ws) {
- wlr_log(L_DEBUG, "sending workspace event");
ipc_event_workspace(last_ws, container, "focus");
if (last_ws->children->length == 0) {
container_workspace_destroy(last_ws);
}
}
+ struct sway_container *last_output = last_focus;
+ if (last_output && last_output->type != C_OUTPUT) {
+ last_output = container_parent(last_output, C_OUTPUT);
+ }
+ struct sway_container *new_output = container;
+ if (new_output && new_output->type != C_OUTPUT) {
+ new_output = container_parent(new_output, C_OUTPUT);
+ }
+ if (new_output && last_output && new_output != last_output
+ && config->mouse_warping && warp) {
+ struct wlr_output *output = new_output->sway_output->wlr_output;
+ double x = container->x + output->lx + container->width / 2.0;
+ double y = container->y + output->ly + container->height / 2.0;
+ if (!wlr_output_layout_contains_point(
+ root_container.sway_root->output_layout,
+ output, seat->cursor->cursor->x, seat->cursor->cursor->y)) {
+ wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);
+ }
+ }
}
if (last_focus && last_focus->type == C_VIEW &&
@@ -347,6 +372,11 @@ void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *containe
seat->has_focus = (container != NULL);
}
+void sway_seat_set_focus(struct sway_seat *seat,
+ struct sway_container *container) {
+ sway_seat_set_focus_warp(seat, container, true);
+}
+
struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container) {
struct sway_seat_container *current = NULL;
struct sway_container *parent = NULL;
diff --git a/sway/meson.build b/sway/meson.build
index e8a192f0..38945b4c 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -13,11 +13,13 @@ sway_sources = files(
'commands/exec.c',
'commands/exec_always.c',
'commands/focus.c',
+ 'commands/focus_follows_mouse.c',
'commands/kill.c',
'commands/include.c',
'commands/input.c',
'commands/layout.c',
'commands/mode.c',
+ 'commands/move.c',
'commands/seat.c',
'commands/seat/attach.c',
'commands/seat/fallback.c',
@@ -63,6 +65,7 @@ sway_sources = files(
'commands/input/xkb_options.c',
'commands/input/xkb_rules.c',
'commands/input/xkb_variant.c',
+ 'commands/mouse_warping.c',
'commands/output.c',
'commands/reload.c',
'commands/workspace.c',
diff --git a/sway/server.c b/sway/server.c
index 9c1671c3..f5cc199c 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -8,7 +8,9 @@
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_gamma_control.h>
+#include <wlr/types/wlr_linux_dmabuf.h>
#include <wlr/types/wlr_layer_shell.h>
+#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_screenshooter.h>
#include <wlr/types/wlr_wl_shell.h>
#include <wlr/types/wlr_xcursor_manager.h>
@@ -54,6 +56,7 @@ bool server_init(struct sway_server *server) {
wlr_screenshooter_create(server->wl_display);
wlr_gamma_control_manager_create(server->wl_display);
+ wlr_primary_selection_device_manager_create(server->wl_display);
server->new_output.notify = handle_new_output;
wl_signal_add(&server->backend->events.new_output, &server->new_output);
@@ -68,6 +71,11 @@ bool server_init(struct sway_server *server) {
&server->xdg_shell_v6_surface);
server->xdg_shell_v6_surface.notify = handle_xdg_shell_v6_surface;
+ server->wl_shell = wlr_wl_shell_create(server->wl_display);
+ wl_signal_add(&server->wl_shell->events.new_surface,
+ &server->wl_shell_surface);
+ server->wl_shell_surface.notify = handle_wl_shell_surface;
+
// TODO make xwayland optional
server->xwayland =
wlr_xwayland_create(server->wl_display, server->compositor);
@@ -91,10 +99,8 @@ bool server_init(struct sway_server *server) {
image->hotspot_y);
}
- server->wl_shell = wlr_wl_shell_create(server->wl_display);
- wl_signal_add(&server->wl_shell->events.new_surface,
- &server->wl_shell_surface);
- server->wl_shell_surface.notify = handle_wl_shell_surface;
+ struct wlr_egl *egl = wlr_backend_get_egl(server->backend);
+ wlr_linux_dmabuf_create(server->wl_display, egl);
server->socket = wl_display_add_socket_auto(server->wl_display);
if (!server->socket) {
@@ -104,7 +110,6 @@ bool server_init(struct sway_server *server) {
}
input_manager = sway_input_manager_create(server);
-
return true;
}
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 746dbf1f..21fe3fb0 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -33,6 +33,23 @@ static list_t *get_bfs_queue() {
return bfs_queue;
}
+const char *container_type_to_str(enum sway_container_type type) {
+ switch (type) {
+ case C_ROOT:
+ return "C_ROOT";
+ case C_OUTPUT:
+ return "C_OUTPUT";
+ case C_WORKSPACE:
+ return "C_WORKSPACE";
+ case C_CONTAINER:
+ return "C_CONTAINER";
+ case C_VIEW:
+ return "C_VIEW";
+ default:
+ return "C_UNKNOWN";
+ }
+}
+
static void notify_new_container(struct sway_container *container) {
wl_signal_emit(&root_container.sway_root->events.new_container, container);
ipc_event_window(container, "new");
@@ -54,6 +71,7 @@ static struct sway_container *container_create(enum sway_container_type type) {
}
wl_signal_init(&c->events.destroy);
+ wl_signal_init(&c->events.reparent);
return c;
}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 588ceb2d..a8941a40 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -106,8 +106,10 @@ struct sway_container *container_reap_empty(struct sway_container *container) {
if (!sway_assert(container, "reaping null container")) {
return NULL;
}
- wlr_log(L_DEBUG, "reaping %p %s", container, container->name);
- while (container->children->length == 0) {
+ wlr_log(L_DEBUG, "Reaping %p %s '%s'", container,
+ container_type_to_str(container->type), container->name);
+ while (container->type != C_ROOT && container->type != C_OUTPUT
+ && container->children->length == 0) {
if (container->type == C_WORKSPACE) {
if (!workspace_is_visible(container)) {
struct sway_container *parent = container->parent;
@@ -138,22 +140,46 @@ struct sway_container *container_remove_child(struct sway_container *child) {
return container_reap_empty(parent);
}
-void container_move_to(struct sway_container* container,
- struct sway_container* destination) {
+void container_move_to(struct sway_container *container,
+ struct sway_container *destination) {
if (container == destination
|| container_has_anscestor(container, destination)) {
return;
}
struct sway_container *old_parent = container_remove_child(container);
container->width = container->height = 0;
- struct sway_container *new_parent =
- container_add_sibling(destination, container);
+ struct sway_container *new_parent;
+ if (destination->type == C_VIEW) {
+ new_parent = container_add_sibling(destination, container);
+ } else {
+ new_parent = destination;
+ container_add_child(destination, container);
+ }
+ wl_signal_emit(&container->events.reparent, old_parent);
+ if (container->type == C_WORKSPACE) {
+ struct sway_seat *seat = sway_input_manager_get_default_seat(
+ input_manager);
+ if (old_parent->children->length == 0) {
+ char *ws_name = workspace_next_name(old_parent->name);
+ struct sway_container *ws =
+ container_workspace_create(old_parent, ws_name);
+ free(ws_name);
+ sway_seat_set_focus(seat, ws);
+ }
+ container_sort_workspaces(new_parent);
+ sway_seat_set_focus(seat, new_parent);
+ }
if (old_parent) {
arrange_windows(old_parent, -1, -1);
}
arrange_windows(new_parent, -1, -1);
}
+void container_move(struct sway_container *container,
+ enum movement_direction dir, int move_amt) {
+ // TODO
+}
+
enum sway_container_layout container_get_default_layout(
struct sway_container *output) {
if (config->default_layout != L_NONE) {
@@ -521,26 +547,6 @@ static struct sway_container *get_swayc_in_direction_under(
}
}
- if (dir == MOVE_PREV || dir == MOVE_NEXT) {
- int focused_idx = index_child(container);
- if (focused_idx == -1) {
- return NULL;
- } else {
- int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) %
- parent->children->length;
- if (desired < 0) {
- desired += parent->children->length;
- }
- return parent->children->items[desired];
- }
- }
-
- // If moving to an adjacent output we need a starting position (since this
- // output might border to multiple outputs).
- //struct wlc_point abs_pos;
- //get_layout_center_position(container, &abs_pos);
-
-
// TODO WLR fullscreen
/*
if (container->type == C_VIEW && swayc_is_fullscreen(container)) {
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 7248fd00..2331dc2b 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -1,3 +1,4 @@
+#include <strings.h>
#include "sway/tree/container.h"
#include "sway/tree/layout.h"
#include "sway/output.h"
@@ -37,3 +38,13 @@ struct sway_container *container_output_destroy(struct sway_container *output) {
container_destroy(output);
return &root_container;
}
+
+struct sway_container *output_by_name(const char *name) {
+ for (int i = 0; i < root_container.children->length; ++i) {
+ struct sway_container *output = root_container.children->items[i];
+ if (strcasecmp(output->name, name) == 0){
+ return output;
+ }
+ }
+ return NULL;
+}