aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c25
-rw-r--r--sway/commands/focus.c11
-rw-r--r--sway/commands/kill.c27
-rw-r--r--sway/commands/move.c184
-rw-r--r--sway/commands/seat.c11
-rw-r--r--sway/commands/split.c76
-rw-r--r--sway/commands/workspace.c2
-rw-r--r--sway/config.c2
-rw-r--r--sway/desktop/layer_shell.c27
-rw-r--r--sway/desktop/output.c100
-rw-r--r--sway/desktop/wl_shell.c61
-rw-r--r--sway/desktop/xdg_shell_v6.c67
-rw-r--r--sway/desktop/xwayland.c136
-rw-r--r--sway/input/cursor.c32
-rw-r--r--sway/input/input-manager.c144
-rw-r--r--sway/input/keyboard.c6
-rw-r--r--sway/input/seat.c251
-rw-r--r--sway/ipc-json.c8
-rw-r--r--sway/ipc-server.c6
-rw-r--r--sway/main.c2
-rw-r--r--sway/meson.build2
-rw-r--r--sway/server.c2
-rw-r--r--sway/tree/container.c56
-rw-r--r--sway/tree/layout.c181
-rw-r--r--sway/tree/output.c12
-rw-r--r--sway/tree/view.c188
-rw-r--r--sway/tree/workspace.c16
27 files changed, 1120 insertions, 515 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 90544220..8156a08e 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -72,23 +72,23 @@ void apply_input_config(struct input_config *input) {
list_add(config->input_configs, input);
}
- sway_input_manager_apply_input_config(input_manager, input);
+ input_manager_apply_input_config(input_manager, input);
}
-void apply_seat_config(struct seat_config *seat) {
+void apply_seat_config(struct seat_config *seat_config) {
int i;
- i = list_seq_find(config->seat_configs, seat_name_cmp, seat->name);
+ i = list_seq_find(config->seat_configs, seat_name_cmp, seat_config->name);
if (i >= 0) {
// merge existing config
struct seat_config *sc = config->seat_configs->items[i];
- merge_seat_config(sc, seat);
- free_seat_config(seat);
- seat = sc;
+ merge_seat_config(sc, seat_config);
+ free_seat_config(seat_config);
+ seat_config = sc;
} else {
- list_add(config->seat_configs, seat);
+ list_add(config->seat_configs, seat_config);
}
- sway_input_manager_apply_seat_config(input_manager, seat);
+ input_manager_apply_seat_config(input_manager, seat_config);
}
/* Keep alphabetized */
@@ -162,7 +162,12 @@ static struct cmd_handler command_handlers[] = {
{ "focus", cmd_focus },
{ "kill", cmd_kill },
{ "layout", cmd_layout },
+ { "move", cmd_move },
{ "reload", cmd_reload },
+ { "split", cmd_split },
+ { "splith", cmd_splith },
+ { "splitt", cmd_splitt },
+ { "splitv", cmd_splitv },
};
static int handler_compare(const void *_a, const void *_b) {
@@ -262,7 +267,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
if (seat == NULL) {
// passing a NULL seat means we just pick the default seat
- seat = sway_input_manager_get_default_seat(input_manager);
+ seat = input_manager_get_default_seat(input_manager);
if (!sway_assert(seat, "could not find a seat to run the command on")) {
return NULL;
}
@@ -340,7 +345,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
// without criteria, the command acts upon the focused
// container
config->handler_context.current_container =
- sway_seat_get_focus_inactive(seat, &root_container);
+ seat_get_focus_inactive(seat, &root_container);
if (!sway_assert(config->handler_context.current_container,
"could not get focus-inactive for root container")) {
return NULL;
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 64f079f4..74d9d535 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;
}
@@ -40,7 +36,7 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
}
if (argc == 0) {
- sway_seat_set_focus(seat, con);
+ seat_set_focus(seat, con);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
@@ -51,9 +47,10 @@ 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);
+ seat_set_focus(seat, next_focus);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/kill.c b/sway/commands/kill.c
index f6774767..46d6e98e 100644
--- a/sway/commands/kill.c
+++ b/sway/commands/kill.c
@@ -3,21 +3,28 @@
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/tree/view.h"
+#include "sway/tree/container.h"
#include "sway/commands.h"
struct cmd_results *cmd_kill(int argc, char **argv) {
- enum sway_container_type type = config->handler_context.current_container->type;
- if (type != C_VIEW && type != C_CONTAINER) {
+ struct sway_container *con =
+ config->handler_context.current_container;
+
+ switch (con->type) {
+ case C_ROOT:
+ case C_OUTPUT:
+ case C_WORKSPACE:
+ case C_TYPES:
return cmd_results_new(CMD_INVALID, NULL,
"Can only kill views and containers with this command");
- }
-
- // TODO close arbitrary containers without a view
- struct sway_view *view =
- config->handler_context.current_container->sway_view;
-
- if (view) {
- view_close(view);
+ break;
+ case C_CONTAINER:
+ con = container_destroy(con);
+ arrange_windows(con, -1, -1);
+ break;
+ case C_VIEW:
+ view_close(con->sway_view);
+ break;
}
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..644c622b
--- /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 = seat_get_focus_inactive(
+ config->handler_context.seat, ws);
+ container_move_to(current, focus);
+ 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 = 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);
+ 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/commands/seat.c b/sway/commands/seat.c
index 45079616..819b769c 100644
--- a/sway/commands/seat.c
+++ b/sway/commands/seat.c
@@ -14,7 +14,8 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
free_seat_config(config->handler_context.seat_config);
config->handler_context.seat_config = new_seat_config(argv[0]);
if (!config->handler_context.seat_config) {
- return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
+ return cmd_results_new(CMD_FAILURE, NULL,
+ "Couldn't allocate config");
}
wlr_log(L_DEBUG, "entering seat block: %s", argv[0]);
return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL);
@@ -28,7 +29,8 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
if (!has_context) {
config->handler_context.seat_config = new_seat_config(argv[0]);
if (!config->handler_context.seat_config) {
- return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
+ return cmd_results_new(CMD_FAILURE, NULL,
+ "Couldn't allocate config");
}
}
@@ -41,7 +43,10 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
} else if (strcasecmp("fallback", argv[1]) == 0) {
res = seat_cmd_fallback(argc_new, argv_new);
} else {
- res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]);
+ res =
+ cmd_results_new(CMD_INVALID,
+ "seat <name>", "Unknown command %s",
+ argv[1]);
}
if (!has_context) {
diff --git a/sway/commands/split.c b/sway/commands/split.c
new file mode 100644
index 00000000..ab8565a9
--- /dev/null
+++ b/sway/commands/split.c
@@ -0,0 +1,76 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/tree/container.h"
+#include "sway/tree/layout.h"
+#include "sway/tree/view.h"
+#include "sway/input/input-manager.h"
+#include "sway/input/seat.h"
+#include "log.h"
+
+static struct cmd_results *do_split(int layout) {
+ struct sway_container *con = config->handler_context.current_container;
+ struct sway_container *parent = container_split(con, layout);
+ arrange_windows(parent, -1, -1);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+struct cmd_results *cmd_split(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) {
+ do_split(L_VERT);
+ } else if (strcasecmp(argv[0], "h") == 0 ||
+ strcasecmp(argv[0], "horizontal") == 0) {
+ do_split(L_HORIZ);
+ } else if (strcasecmp(argv[0], "t") == 0 ||
+ strcasecmp(argv[0], "toggle") == 0) {
+ struct sway_container *focused =
+ config->handler_context.current_container;
+
+ if (focused->parent->layout == L_VERT) {
+ do_split(L_HORIZ);
+ } else {
+ do_split(L_VERT);
+ }
+ } else {
+ error = cmd_results_new(CMD_FAILURE, "split",
+ "Invalid split command (expected either horizontal or vertical).");
+ return error;
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+struct cmd_results *cmd_splitv(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) {
+ return error;
+ }
+ return do_split(L_VERT);
+}
+
+struct cmd_results *cmd_splith(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) {
+ return error;
+ }
+ return do_split(L_HORIZ);
+}
+
+struct cmd_results *cmd_splitt(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) {
+ return error;
+ }
+
+ struct sway_container *con = config->handler_context.current_container;
+
+ if (con->parent->layout == L_VERT) {
+ return do_split(L_HORIZ);
+ } else {
+ return do_split(L_VERT);
+ }
+}
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index 8f39e5fc..aa4096f7 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -91,7 +91,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
}
workspace_switch(ws);
current_container =
- sway_seat_get_focus(config->handler_context.seat);
+ seat_get_focus(config->handler_context.seat);
struct sway_container *new_output = container_parent(current_container, C_OUTPUT);
if (config->mouse_warping && old_output != new_output) {
diff --git a/sway/config.c b/sway/config.c
index 0eecf7f6..90b833ab 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -125,7 +125,7 @@ static void destroy_removed_seats(struct sway_config *old_config,
seat_name_cmp, seat_config->name) < 0) {
seat = input_manager_get_seat(input_manager,
seat_config->name);
- sway_seat_destroy(seat);
+ seat_destroy(seat);
}
}
}
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index c18f51c7..3c7b45f7 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -7,6 +7,8 @@
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output.h>
#include <wlr/util/log.h>
+#include "sway/input/input-manager.h"
+#include "sway/input/seat.h"
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/server.h"
@@ -187,6 +189,31 @@ void arrange_layers(struct sway_output *output) {
&usable_area, false);
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
&usable_area, false);
+
+ // Find topmost keyboard interactive layer, if such a layer exists
+ uint32_t layers_above_shell[] = {
+ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
+ ZWLR_LAYER_SHELL_V1_LAYER_TOP,
+ };
+ size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
+ struct sway_layer_surface *layer, *topmost = NULL;
+ for (size_t i = 0; i < nlayers; ++i) {
+ wl_list_for_each_reverse(layer,
+ &output->layers[layers_above_shell[i]], link) {
+ if (layer->layer_surface->current.keyboard_interactive) {
+ topmost = layer;
+ break;
+ }
+ }
+ if (topmost != NULL) {
+ break;
+ }
+ }
+
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &input_manager->seats, link) {
+ seat_set_focus_layer(seat, topmost ? topmost->layer_surface : NULL);
+ }
}
static void handle_output_destroy(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 0d706c52..10ed1f6d 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -39,6 +39,32 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh,
}
}
+/**
+ * Checks whether a surface at (lx, ly) intersects an output. If `box` is not
+ * NULL, it populates it with the surface box in the output, in output-local
+ * coordinates.
+ */
+static bool surface_intersect_output(struct wlr_surface *surface,
+ struct wlr_output_layout *output_layout, struct wlr_output *wlr_output,
+ double lx, double ly, float rotation, struct wlr_box *box) {
+ double ox = lx, oy = ly;
+ wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy);
+
+ if (box != NULL) {
+ box->x = ox * wlr_output->scale;
+ box->y = oy * wlr_output->scale;
+ box->width = surface->current->width * wlr_output->scale;
+ box->height = surface->current->height * wlr_output->scale;
+ }
+
+ struct wlr_box layout_box = {
+ .x = lx, .y = ly,
+ .width = surface->current->width, .height = surface->current->height,
+ };
+ wlr_box_rotated_bounds(&layout_box, rotation, &layout_box);
+ return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box);
+}
+
static void render_surface(struct wlr_surface *surface,
struct wlr_output *wlr_output, struct timespec *when,
double lx, double ly, float rotation) {
@@ -48,29 +74,21 @@ static void render_surface(struct wlr_surface *surface,
if (!wlr_surface_has_buffer(surface)) {
return;
}
+
struct wlr_output_layout *layout = root_container.sway_root->output_layout;
- int width = surface->current->width;
- int height = surface->current->height;
- int render_width = width * wlr_output->scale;
- int render_height = height * wlr_output->scale;
- int owidth, oheight;
- wlr_output_effective_resolution(wlr_output, &owidth, &oheight);
-
- // FIXME: view coords are inconsistently assumed to be in output or layout coords
- struct wlr_box layout_box = {
- .x = lx + wlr_output->lx, .y = ly + wlr_output->ly,
- .width = render_width, .height = render_height,
- };
- if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) {
- struct wlr_box render_box = {
- .x = lx, .y = ly,
- .width = render_width, .height = render_height
- };
+
+ struct wlr_box box;
+ bool intersects = surface_intersect_output(surface, layout, wlr_output,
+ lx, ly, rotation, &box);
+ if (intersects) {
float matrix[9];
- wlr_matrix_project_box(matrix, &render_box, surface->current->transform,
- 0, wlr_output->transform_matrix);
- wlr_render_texture_with_matrix(renderer, surface->texture, matrix,
- 1.0f); // TODO: configurable alpha
+ enum wl_output_transform transform =
+ wlr_output_transform_invert(surface->current->transform);
+ wlr_matrix_project_box(matrix, &box, transform, rotation,
+ wlr_output->transform_matrix);
+
+ // TODO: configurable alpha
+ wlr_render_texture_with_matrix(renderer, surface->texture, matrix, 1.0f);
wlr_surface_send_frame_done(surface, when);
}
@@ -80,9 +98,8 @@ static void render_surface(struct wlr_surface *surface,
struct wlr_surface_state *state = subsurface->surface->current;
double sx = state->subsurface_position.x;
double sy = state->subsurface_position.y;
- double sw = state->buffer_width / state->scale;
- double sh = state->buffer_height / state->scale;
- rotate_child_position(&sx, &sy, sw, sh, width, height, rotation);
+ rotate_child_position(&sx, &sy, state->width, state->height,
+ surface->current->width, surface->current->height, rotation);
render_surface(subsurface->surface, wlr_output, when,
lx + sx, ly + sy, rotation);
@@ -228,10 +245,13 @@ 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));
+ seat_get_focus_inactive(seat, output->swayc);
+ 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,
@@ -240,15 +260,15 @@ static void render_output(struct sway_output *output, struct timespec *when,
container_descendants(workspace, C_VIEW, render_view, &rdata);
// render unmanaged views on top
- struct sway_view *view;
- wl_list_for_each(view, &root_container.sway_root->unmanaged_views,
- unmanaged_view_link) {
- if (view->type != SWAY_XWAYLAND_VIEW) {
+ struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
+ struct sway_xwayland_unmanaged *sway_surface;
+ wl_list_for_each(sway_surface, unmanaged, link) {
+ struct wlr_xwayland_surface *xsurface =
+ sway_surface->wlr_xwayland_surface;
+ if (xsurface->surface == NULL) {
continue;
}
- struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
-
const struct wlr_box view_box = {
.x = xsurface->x,
.y = xsurface->y,
@@ -260,7 +280,7 @@ static void render_output(struct sway_output *output, struct timespec *when,
continue;
}
- render_surface(view->surface, wlr_output, &output->last_frame,
+ render_surface(xsurface->surface, wlr_output, &output->last_frame,
view_box.x - output_box->x, view_box.y - output_box->y, 0);
}
@@ -338,6 +358,12 @@ static void handle_transform(struct wl_listener *listener, void *data) {
arrange_windows(output->swayc, -1, -1);
}
+static void handle_scale(struct wl_listener *listener, void *data) {
+ struct sway_output *output = wl_container_of(listener, output, scale);
+ arrange_layers(output);
+ arrange_windows(output->swayc, -1, -1);
+}
+
void handle_new_output(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
@@ -370,7 +396,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
wl_list_init(&output->layers[i]);
}
- sway_input_manager_configure_xcursor(input_manager);
+ input_manager_configure_xcursor(input_manager);
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
@@ -378,6 +404,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->mode.notify = handle_mode;
wl_signal_add(&wlr_output->events.transform, &output->transform);
output->transform.notify = handle_transform;
+ wl_signal_add(&wlr_output->events.scale, &output->scale);
+ output->scale.notify = handle_scale;
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
output->damage_frame.notify = damage_handle_frame;
diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c
index 4fcc6317..6528a397 100644
--- a/sway/desktop/wl_shell.c
+++ b/sway/desktop/wl_shell.c
@@ -30,28 +30,18 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {
}
}
-static void set_size(struct sway_view *view, int width, int height) {
+static void configure(struct sway_view *view, double ox, double oy, int width,
+ int height) {
if (!assert_wl_shell(view)) {
return;
}
+ view_update_position(view, ox, oy);
view->sway_wl_shell_surface->pending_width = width;
view->sway_wl_shell_surface->pending_height = height;
wlr_wl_shell_surface_configure(view->wlr_wl_shell_surface, 0, width, height);
}
-static void set_position(struct sway_view *view, double ox, double oy) {
- if (!assert_wl_shell(view)) {
- return;
- }
- view->swayc->x = ox;
- view->swayc->y = oy;
-}
-
-static void set_activated(struct sway_view *view, bool activated) {
- // no way to activate wl_shell
-}
-
-static void close(struct sway_view *view) {
+static void _close(struct sway_view *view) {
if (!assert_wl_shell(view)) {
return;
}
@@ -59,14 +49,20 @@ static void close(struct sway_view *view) {
wl_client_destroy(view->wlr_wl_shell_surface->client);
}
+static const struct sway_view_impl view_impl = {
+ .get_prop = get_prop,
+ .configure = configure,
+ .close = _close,
+};
+
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_wl_shell_surface *sway_surface =
wl_container_of(listener, sway_surface, commit);
struct sway_view *view = sway_surface->view;
// NOTE: We intentionally discard the view's desired width here
// TODO: Let floating views do whatever
- view->width = sway_surface->pending_width;
- view->height = sway_surface->pending_height;
+ view_update_size(view, sway_surface->pending_width,
+ sway_surface->pending_height);
view_damage_from(view);
}
@@ -75,15 +71,13 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_container_of(listener, sway_surface, destroy);
wl_list_remove(&sway_surface->commit.link);
wl_list_remove(&sway_surface->destroy.link);
- struct sway_container *parent = container_view_destroy(sway_surface->view->swayc);
- free(sway_surface->view);
+ view_destroy(sway_surface->view);
free(sway_surface);
- arrange_windows(parent, -1, -1);
}
void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
- struct sway_server *server = wl_container_of(
- listener, server, wl_shell_surface);
+ struct sway_server *server = wl_container_of(listener, server,
+ wl_shell_surface);
struct wlr_wl_shell_surface *shell_surface = data;
if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) {
@@ -103,20 +97,13 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
return;
}
- struct sway_view *sway_view = calloc(1, sizeof(struct sway_view));
- if (!sway_assert(sway_view, "Failed to allocate view!")) {
+ struct sway_view *view = view_create(SWAY_WL_SHELL_VIEW, &view_impl);
+ if (!sway_assert(view, "Failed to allocate view")) {
return;
}
- sway_view->type = SWAY_WL_SHELL_VIEW;
- sway_view->iface.get_prop = get_prop;
- sway_view->iface.set_size = set_size;
- sway_view->iface.set_position = set_position;
- sway_view->iface.set_activated = set_activated;
- sway_view->iface.close = close;
- sway_view->wlr_wl_shell_surface = shell_surface;
- sway_view->sway_wl_shell_surface = sway_surface;
- sway_view->surface = shell_surface->surface;
- sway_surface->view = sway_view;
+ view->wlr_wl_shell_surface = shell_surface;
+ view->sway_wl_shell_surface = sway_surface;
+ sway_surface->view = view;
// TODO:
// - Wire up listeners
@@ -132,11 +119,5 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
sway_surface->destroy.notify = handle_destroy;
wl_signal_add(&shell_surface->events.destroy, &sway_surface->destroy);
- 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 *cont = container_view_create(focus, sway_view);
- sway_view->swayc = cont;
-
- arrange_windows(cont->parent, -1, -1);
- sway_input_manager_set_focus(input_manager, cont);
+ view_map(view, shell_surface->surface);
}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 713437f2..49305b39 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -30,23 +30,18 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {
}
}
-static void set_size(struct sway_view *view, int width, int height) {
+static void configure(struct sway_view *view, double ox, double oy, int width,
+ int height) {
if (!assert_xdg(view)) {
return;
}
+
+ view_update_position(view, ox, oy);
view->sway_xdg_surface_v6->pending_width = width;
view->sway_xdg_surface_v6->pending_height = height;
wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height);
}
-static void set_position(struct sway_view *view, double ox, double oy) {
- if (!assert_xdg(view)) {
- return;
- }
- view->swayc->x = ox;
- view->swayc->y = oy;
-}
-
static void set_activated(struct sway_view *view, bool activated) {
if (!assert_xdg(view)) {
return;
@@ -57,7 +52,7 @@ static void set_activated(struct sway_view *view, bool activated) {
}
}
-static void close(struct sway_view *view) {
+static void _close(struct sway_view *view) {
if (!assert_xdg(view)) {
return;
}
@@ -67,6 +62,13 @@ static void close(struct sway_view *view) {
}
}
+static const struct sway_view_impl view_impl = {
+ .get_prop = get_prop,
+ .configure = configure,
+ .set_activated = set_activated,
+ .close = _close,
+};
+
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xdg_surface_v6 *sway_surface =
wl_container_of(listener, sway_surface, commit);
@@ -74,37 +76,22 @@ static void handle_commit(struct wl_listener *listener, void *data) {
// NOTE: We intentionally discard the view's desired width here
// TODO: Store this for restoration when moving to floating plane
// TODO: Let floating views do whatever
- view->width = sway_surface->pending_width;
- view->height = sway_surface->pending_height;
+ view_update_size(view, sway_surface->pending_width,
+ sway_surface->pending_height);
view_damage_from(view);
}
static void handle_unmap(struct wl_listener *listener, void *data) {
struct sway_xdg_surface_v6 *sway_surface =
wl_container_of(listener, sway_surface, unmap);
- view_damage_whole(sway_surface->view);
- container_view_destroy(sway_surface->view->swayc);
- sway_surface->view->swayc = NULL;
- sway_surface->view->surface = NULL;
+ view_unmap(sway_surface->view);
}
static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xdg_surface_v6 *sway_surface =
wl_container_of(listener, sway_surface, map);
struct sway_view *view = sway_surface->view;
-
- sway_surface->view->surface = view->wlr_xdg_surface_v6->surface;
-
- container_view_destroy(view->swayc);
-
- 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 *cont = container_view_create(focus, view);
- view->swayc = cont;
- arrange_windows(cont->parent, -1, -1);
- sway_input_manager_set_focus(input_manager, cont);
-
- view_damage_whole(sway_surface->view);
+ view_map(view, view->wlr_xdg_surface_v6->surface);
}
static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -112,8 +99,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_container_of(listener, sway_xdg_surface, destroy);
wl_list_remove(&sway_xdg_surface->commit.link);
wl_list_remove(&sway_xdg_surface->destroy.link);
- container_view_destroy(sway_xdg_surface->view->swayc);
- free(sway_xdg_surface->view);
+ wl_list_remove(&sway_xdg_surface->map.link);
+ wl_list_remove(&sway_xdg_surface->unmap.link);
+ view_destroy(sway_xdg_surface->view);
free(sway_xdg_surface);
}
@@ -138,23 +126,16 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
return;
}
- struct sway_view *sway_view = calloc(1, sizeof(struct sway_view));
- if (!sway_assert(sway_view, "Failed to allocate view!")) {
+ struct sway_view *view = view_create(SWAY_XDG_SHELL_V6_VIEW, &view_impl);
+ if (!sway_assert(view, "Failed to allocate view")) {
return;
}
- sway_view->type = SWAY_XDG_SHELL_V6_VIEW;
- sway_view->iface.get_prop = get_prop;
- sway_view->iface.set_size = set_size;
- sway_view->iface.set_position = set_position;
- sway_view->iface.set_activated = set_activated;
- sway_view->iface.close = close;
- sway_view->wlr_xdg_surface_v6 = xdg_surface;
- sway_view->sway_xdg_surface_v6 = sway_surface;
- sway_surface->view = sway_view;
+ view->wlr_xdg_surface_v6 = xdg_surface;
+ view->sway_xdg_surface_v6 = sway_surface;
+ sway_surface->view = view;
// TODO:
// - Look up pid and open on appropriate workspace
- // - Set new view to maximized so it behaves nicely
// - Criteria
sway_surface->commit.notify = handle_commit;
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 273ca2bf..bfef68cf 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -14,6 +14,33 @@
#include "sway/input/input-manager.h"
#include "log.h"
+static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
+ struct sway_xwayland_unmanaged *sway_surface =
+ wl_container_of(listener, sway_surface, destroy);
+ wl_list_remove(&sway_surface->destroy.link);
+ wl_list_remove(&sway_surface->link);
+ free(sway_surface);
+}
+
+static void create_unmanaged(struct wlr_xwayland_surface *xsurface) {
+ struct sway_xwayland_unmanaged *sway_surface =
+ calloc(1, sizeof(struct sway_xwayland_unmanaged));
+ if (!sway_assert(sway_surface, "Failed to allocate surface")) {
+ return;
+ }
+
+ sway_surface->wlr_xwayland_surface = xsurface;
+
+ wl_signal_add(&xsurface->events.destroy, &sway_surface->destroy);
+ sway_surface->destroy.notify = unmanaged_handle_destroy;
+
+ wl_list_insert(&root_container.sway_root->xwayland_unmanaged,
+ &sway_surface->link);
+
+ // TODO: damage tracking
+}
+
+
static bool assert_xwayland(struct sway_view *view) {
return sway_assert(view->type == SWAY_XWAYLAND_VIEW,
"Expected xwayland view!");
@@ -33,22 +60,13 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {
}
}
-static void set_size(struct sway_view *view, int width, int height) {
+static void configure(struct sway_view *view, double ox, double oy, int width,
+ int height) {
if (!assert_xwayland(view)) {
return;
}
- view->sway_xwayland_surface->pending_width = width;
- view->sway_xwayland_surface->pending_height = height;
-
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
- wlr_xwayland_surface_configure(xsurface, xsurface->x, xsurface->y,
- width, height);
-}
-static void set_position(struct sway_view *view, double ox, double oy) {
- if (!assert_xwayland(view)) {
- return;
- }
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
if (!sway_assert(output, "view must be within tree to set position")) {
return;
@@ -64,13 +82,12 @@ static void set_position(struct sway_view *view, double ox, double oy) {
return;
}
- view->swayc->x = ox;
- view->swayc->y = oy;
+ view_update_position(view, ox, oy);
- wlr_xwayland_surface_configure(view->wlr_xwayland_surface,
- ox + loutput->x, oy + loutput->y,
- view->wlr_xwayland_surface->width,
- view->wlr_xwayland_surface->height);
+ view->sway_xwayland_surface->pending_width = width;
+ view->sway_xwayland_surface->pending_height = height;
+ wlr_xwayland_surface_configure(xsurface, ox + loutput->x, oy + loutput->y,
+ width, height);
}
static void set_activated(struct sway_view *view, bool activated) {
@@ -81,77 +98,58 @@ static void set_activated(struct sway_view *view, bool activated) {
wlr_xwayland_surface_activate(surface, activated);
}
-static void close_view(struct sway_view *view) {
+static void _close(struct sway_view *view) {
if (!assert_xwayland(view)) {
return;
}
wlr_xwayland_surface_close(view->wlr_xwayland_surface);
}
+static const struct sway_view_impl view_impl = {
+ .get_prop = get_prop,
+ .configure = configure,
+ .set_activated = set_activated,
+ .close = _close,
+};
+
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, commit);
struct sway_view *view = sway_surface->view;
// NOTE: We intentionally discard the view's desired width here
// TODO: Let floating views do whatever
- view->width = sway_surface->pending_width;
- view->height = sway_surface->pending_height;
+ view_update_size(view, sway_surface->pending_width,
+ sway_surface->pending_height);
view_damage_from(view);
}
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, destroy);
-
wl_list_remove(&sway_surface->commit.link);
wl_list_remove(&sway_surface->destroy.link);
wl_list_remove(&sway_surface->request_configure.link);
- wl_list_remove(&sway_surface->view->unmanaged_view_link);
- container_view_destroy(sway_surface->view->swayc);
- sway_surface->view->swayc = NULL;
- sway_surface->view->surface = NULL;
+ wl_list_remove(&sway_surface->map.link);
+ wl_list_remove(&sway_surface->unmap.link);
+ view_destroy(sway_surface->view);
+ free(sway_surface);
}
static void handle_unmap(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, unmap);
- view_damage_whole(sway_surface->view);
- wl_list_remove(&sway_surface->view->unmanaged_view_link);
- wl_list_init(&sway_surface->view->unmanaged_view_link);
- container_view_destroy(sway_surface->view->swayc);
- sway_surface->view->swayc = NULL;
- sway_surface->view->surface = NULL;
+ view_unmap(sway_surface->view);
}
static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, map);
struct wlr_xwayland_surface *xsurface = data;
-
- sway_surface->view->surface = xsurface->surface;
+ struct sway_view *view = sway_surface->view;
// put it back into the tree
- if (wlr_xwayland_surface_is_unmanaged(xsurface) ||
- xsurface->override_redirect) {
- wl_list_remove(&sway_surface->view->unmanaged_view_link);
- wl_list_insert(&root_container.sway_root->unmanaged_views,
- &sway_surface->view->unmanaged_view_link);
- } else {
- 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 *cont = container_view_create(focus, view);
- view->swayc = cont;
- arrange_windows(cont->parent, -1, -1);
- sway_input_manager_set_focus(input_manager, cont);
- }
-
- view_damage_whole(sway_surface->view);
+ wlr_xwayland_surface_set_maximized(xsurface, true);
+ view_map(view, xsurface->surface);
}
static void handle_request_configure(struct wl_listener *listener, void *data) {
@@ -171,34 +169,32 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
listener, server, xwayland_surface);
struct wlr_xwayland_surface *xsurface = data;
+ if (wlr_xwayland_surface_is_unmanaged(xsurface) ||
+ xsurface->override_redirect) {
+ wlr_log(L_DEBUG, "New xwayland unmanaged surface");
+ create_unmanaged(xsurface);
+ return;
+ }
+
wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'",
- xsurface->title, xsurface->class);
+ xsurface->title, xsurface->class);
struct sway_xwayland_surface *sway_surface =
calloc(1, sizeof(struct sway_xwayland_surface));
- if (!sway_assert(sway_surface, "Failed to allocate surface!")) {
+ if (!sway_assert(sway_surface, "Failed to allocate surface")) {
return;
}
- struct sway_view *sway_view = calloc(1, sizeof(struct sway_view));
- if (!sway_assert(sway_view, "Failed to allocate view!")) {
+ struct sway_view *view = view_create(SWAY_XWAYLAND_VIEW, &view_impl);
+ if (!sway_assert(view, "Failed to allocate view")) {
return;
}
- sway_view->type = SWAY_XWAYLAND_VIEW;
- sway_view->iface.get_prop = get_prop;
- sway_view->iface.set_size = set_size;
- sway_view->iface.set_position = set_position;
- sway_view->iface.set_activated = set_activated;
- sway_view->iface.close = close_view;
- sway_view->wlr_xwayland_surface = xsurface;
- sway_view->sway_xwayland_surface = sway_surface;
- sway_surface->view = sway_view;
-
- wl_list_init(&sway_view->unmanaged_view_link);
+ view->wlr_xwayland_surface = xsurface;
+ view->sway_xwayland_surface = sway_surface;
+ sway_surface->view = view;
// TODO:
// - Look up pid and open on appropriate workspace
- // - Set new view to maximized so it behaves nicely
// - Criteria
wl_signal_add(&xsurface->surface->events.commit, &sway_surface->commit);
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index d608a9cf..9229e92d 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -47,14 +47,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,
static struct sway_container *container_at_cursor(struct sway_cursor *cursor,
struct wlr_surface **surface, double *sx, double *sy) {
// check for unmanaged views first
- 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 wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
+ struct sway_xwayland_unmanaged *sway_surface;
+ wl_list_for_each_reverse(sway_surface, unmanaged, link) {
+ struct wlr_xwayland_surface *xsurface =
+ sway_surface->wlr_xwayland_surface;
+ if (xsurface->surface == NULL) {
continue;
}
- struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
struct wlr_box box = {
.x = xsurface->x,
.y = xsurface->y,
@@ -84,7 +85,7 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor,
// find the focused workspace on the output for this seat
struct sway_container *ws =
- sway_seat_get_focus_inactive(cursor->seat, output->swayc);
+ seat_get_focus_inactive(cursor->seat, output->swayc);
if (ws && ws->type != C_WORKSPACE) {
ws = container_parent(ws, C_WORKSPACE);
}
@@ -129,7 +130,7 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,
double 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);
+ seat_set_focus_warp(cursor->seat, c, false);
}
// reset cursor if switching between clients
@@ -179,27 +180,32 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
double sx, sy;
struct sway_container *cont =
container_at_cursor(cursor, &surface, &sx, &sy);
+ if (surface && wlr_surface_is_layer_surface(surface)) {
+ struct wlr_layer_surface *layer =
+ wlr_layer_surface_from_wlr_surface(surface);
+ if (layer->current.keyboard_interactive) {
+ seat_set_focus_layer(cursor->seat, layer);
+ return;
+ }
+ }
// 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);
+ struct sway_container *old_ws = 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);
+ seat_set_focus(cursor->seat, cont);
}
} else {
- sway_seat_set_focus(cursor->seat, cont);
+ seat_set_focus(cursor->seat, cont);
}
wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec,
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index d421a03f..c3507f65 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -26,7 +26,7 @@ struct seat_config *current_seat_config = NULL;
struct sway_seat *input_manager_current_seat(struct sway_input_manager *input) {
struct sway_seat *seat = config->handler_context.seat;
if (!seat) {
- seat = sway_input_manager_get_default_seat(input_manager);
+ seat = input_manager_get_default_seat(input_manager);
}
return seat;
}
@@ -40,7 +40,7 @@ struct sway_seat *input_manager_get_seat(
}
}
- return sway_seat_create(input, seat_name);
+ return seat_create(input, seat_name);
}
static char *get_device_identifier(struct wlr_input_device *device) {
@@ -83,7 +83,8 @@ static struct sway_input_device *input_sway_device_from_wlr(
static bool input_has_seat_configuration(struct sway_input_manager *input) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- if (seat->config) {
+ struct seat_config *seat_config = seat_get_config(seat);
+ if (seat_config) {
return true;
}
}
@@ -91,9 +92,10 @@ static bool input_has_seat_configuration(struct sway_input_manager *input) {
return false;
}
-static void sway_input_manager_libinput_config_pointer(struct sway_input_device *input_device) {
+static void input_manager_libinput_config_pointer(
+ struct sway_input_device *input_device) {
struct wlr_input_device *wlr_device = input_device->wlr_device;
- struct input_config *ic = input_device->config;
+ struct input_config *ic = input_device_get_config(input_device);
struct libinput_device *libinput_device;
if (!ic || !wlr_input_device_is_libinput(wlr_device)) {
@@ -101,22 +103,27 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device
}
libinput_device = wlr_libinput_get_device_handle(wlr_device);
- wlr_log(L_DEBUG, "sway_input_manager_libinput_config_pointer(%s)", ic->identifier);
+ wlr_log(L_DEBUG, "input_manager_libinput_config_pointer(%s)",
+ ic->identifier);
if (ic->accel_profile != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)",
ic->identifier, ic->accel_profile);
- libinput_device_config_accel_set_profile(libinput_device, ic->accel_profile);
+ libinput_device_config_accel_set_profile(libinput_device,
+ ic->accel_profile);
}
if (ic->click_method != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)",
ic->identifier, ic->click_method);
- libinput_device_config_click_set_method(libinput_device, ic->click_method);
+ libinput_device_config_click_set_method(libinput_device,
+ ic->click_method);
}
if (ic->drag_lock != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
+ wlr_log(L_DEBUG,
+ "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
ic->identifier, ic->click_method);
- libinput_device_config_tap_set_drag_lock_enabled(libinput_device, ic->drag_lock);
+ libinput_device_config_tap_set_drag_lock_enabled(libinput_device,
+ ic->drag_lock);
}
if (ic->dwt != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)",
@@ -124,34 +131,43 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device
libinput_device_config_dwt_set_enabled(libinput_device, ic->dwt);
}
if (ic->left_handed != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) left_handed_set_enabled(%d)",
+ wlr_log(L_DEBUG,
+ "libinput_config_pointer(%s) left_handed_set_enabled(%d)",
ic->identifier, ic->left_handed);
- libinput_device_config_left_handed_set(libinput_device, ic->left_handed);
+ libinput_device_config_left_handed_set(libinput_device,
+ ic->left_handed);
}
if (ic->middle_emulation != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)",
+ wlr_log(L_DEBUG,
+ "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)",
ic->identifier, ic->middle_emulation);
- libinput_device_config_middle_emulation_set_enabled(libinput_device, ic->middle_emulation);
+ libinput_device_config_middle_emulation_set_enabled(libinput_device,
+ ic->middle_emulation);
}
if (ic->natural_scroll != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)",
+ wlr_log(L_DEBUG,
+ "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)",
ic->identifier, ic->natural_scroll);
- libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, ic->natural_scroll);
+ libinput_device_config_scroll_set_natural_scroll_enabled(
+ libinput_device, ic->natural_scroll);
}
if (ic->pointer_accel != FLT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)",
ic->identifier, ic->pointer_accel);
- libinput_device_config_accel_set_speed(libinput_device, ic->pointer_accel);
+ libinput_device_config_accel_set_speed(libinput_device,
+ ic->pointer_accel);
}
if (ic->scroll_method != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)",
ic->identifier, ic->scroll_method);
- libinput_device_config_scroll_set_method(libinput_device, ic->scroll_method);
+ libinput_device_config_scroll_set_method(libinput_device,
+ ic->scroll_method);
}
if (ic->send_events != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)",
ic->identifier, ic->send_events);
- libinput_device_config_send_events_set_mode(libinput_device, ic->send_events);
+ libinput_device_config_send_events_set_mode(libinput_device,
+ ic->send_events);
}
if (ic->tap != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)",
@@ -175,12 +191,11 @@ static void handle_device_destroy(struct wl_listener *listener, void *data) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input_manager->seats, link) {
- sway_seat_remove_device(seat, input_device);
+ seat_remove_device(seat, input_device);
}
wl_list_remove(&input_device->link);
wl_list_remove(&input_device->device_destroy.link);
- free_input_config(input_device->config);
free(input_device->identifier);
free(input_device);
}
@@ -203,44 +218,36 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
wlr_log(L_DEBUG, "adding device: '%s'",
input_device->identifier);
- // find config
- for (int i = 0; i < config->input_configs->length; ++i) {
- struct input_config *input_config = config->input_configs->items[i];
- if (strcmp(input_config->identifier, input_device->identifier) == 0) {
- free_input_config(input_device->config);
- input_device->config = copy_input_config(input_config);
- break;
- }
- }
-
if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
- sway_input_manager_libinput_config_pointer(input_device);
+ input_manager_libinput_config_pointer(input_device);
}
struct sway_seat *seat = NULL;
if (!input_has_seat_configuration(input)) {
wlr_log(L_DEBUG, "no seat configuration, using default seat");
seat = input_manager_get_seat(input, default_seat);
- sway_seat_add_device(seat, input_device);
+ seat_add_device(seat, input_device);
return;
}
bool added = false;
wl_list_for_each(seat, &input->seats, link) {
- bool has_attachment = seat->config &&
- (seat_config_get_attachment(seat->config, input_device->identifier) ||
- seat_config_get_attachment(seat->config, "*"));
+ struct seat_config *seat_config = seat_get_config(seat);
+ bool has_attachment = seat_config &&
+ (seat_config_get_attachment(seat_config, input_device->identifier) ||
+ seat_config_get_attachment(seat_config, "*"));
if (has_attachment) {
- sway_seat_add_device(seat, input_device);
+ seat_add_device(seat, input_device);
added = true;
}
}
if (!added) {
wl_list_for_each(seat, &input->seats, link) {
- if (seat->config && seat->config->fallback == 1) {
- sway_seat_add_device(seat, input_device);
+ struct seat_config *seat_config = seat_get_config(seat);
+ if (seat_config && seat_config->fallback == 1) {
+ seat_add_device(seat, input_device);
added = true;
}
}
@@ -256,7 +263,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
input_device->device_destroy.notify = handle_device_destroy;
}
-struct sway_input_manager *sway_input_manager_create(
+struct sway_input_manager *input_manager_create(
struct sway_server *server) {
struct sway_input_manager *input =
calloc(1, sizeof(struct sway_input_manager));
@@ -277,11 +284,11 @@ struct sway_input_manager *sway_input_manager_create(
return input;
}
-bool sway_input_manager_has_focus(struct sway_input_manager *input,
+bool input_manager_has_focus(struct sway_input_manager *input,
struct sway_container *container) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- if (sway_seat_get_focus(seat) == container) {
+ if (seat_get_focus(seat) == container) {
return true;
}
}
@@ -289,35 +296,32 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input,
return false;
}
-void sway_input_manager_set_focus(struct sway_input_manager *input,
+void input_manager_set_focus(struct sway_input_manager *input,
struct sway_container *container) {
struct sway_seat *seat ;
wl_list_for_each(seat, &input->seats, link) {
- sway_seat_set_focus(seat, container);
+ seat_set_focus(seat, container);
}
}
-void sway_input_manager_apply_input_config(struct sway_input_manager *input,
+void input_manager_apply_input_config(struct sway_input_manager *input,
struct input_config *input_config) {
struct sway_input_device *input_device = NULL;
wl_list_for_each(input_device, &input->devices, link) {
if (strcmp(input_device->identifier, input_config->identifier) == 0) {
- free_input_config(input_device->config);
- input_device->config = copy_input_config(input_config);
-
if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
- sway_input_manager_libinput_config_pointer(input_device);
+ input_manager_libinput_config_pointer(input_device);
}
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- sway_seat_configure_device(seat, input_device);
+ seat_configure_device(seat, input_device);
}
}
}
}
-void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
+void input_manager_apply_seat_config(struct sway_input_manager *input,
struct seat_config *seat_config) {
wlr_log(L_DEBUG, "applying new seat config for seat %s",
seat_config->name);
@@ -326,7 +330,7 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
return;
}
- sway_seat_set_config(seat, seat_config);
+ seat_apply_config(seat, seat_config);
// for every device, try to add it to a seat and if no seat has it
// attached, add it to the fallback seats.
@@ -335,11 +339,12 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
list_t *seat_list = create_list();
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- if (!seat->config) {
+ struct seat_config *seat_config = seat_get_config(seat);
+ if (!seat_config) {
continue;
}
- if (seat_config_get_attachment(seat->config, "*") ||
- seat_config_get_attachment(seat->config,
+ if (seat_config_get_attachment(seat_config, "*") ||
+ seat_config_get_attachment(seat_config,
input_device->identifier)) {
list_add(seat_list, seat);
}
@@ -355,17 +360,18 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
}
}
if (attached) {
- sway_seat_add_device(seat, input_device);
+ seat_add_device(seat, input_device);
} else {
- sway_seat_remove_device(seat, input_device);
+ seat_remove_device(seat, input_device);
}
}
} else {
wl_list_for_each(seat, &input->seats, link) {
- if (seat->config && seat->config->fallback == 1) {
- sway_seat_add_device(seat, input_device);
+ struct seat_config *seat_config = seat_get_config(seat);
+ if (seat_config && seat_config->fallback == 1) {
+ seat_add_device(seat, input_device);
} else {
- sway_seat_remove_device(seat, input_device);
+ seat_remove_device(seat, input_device);
}
}
}
@@ -373,14 +379,14 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
}
}
-void sway_input_manager_configure_xcursor(struct sway_input_manager *input) {
+void input_manager_configure_xcursor(struct sway_input_manager *input) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- sway_seat_configure_xcursor(seat);
+ seat_configure_xcursor(seat);
}
}
-struct sway_seat *sway_input_manager_get_default_seat(
+struct sway_seat *input_manager_get_default_seat(
struct sway_input_manager *input) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
@@ -390,3 +396,15 @@ struct sway_seat *sway_input_manager_get_default_seat(
}
return seat;
}
+
+struct input_config *input_device_get_config(struct sway_input_device *device) {
+ struct input_config *input_config = NULL;
+ for (int i = 0; i < config->input_configs->length; ++i) {
+ input_config = config->input_configs->items[i];
+ if (strcmp(input_config->identifier, device->identifier) == 0) {
+ return input_config;
+ }
+ }
+
+ return NULL;
+}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 99685052..dbb0c359 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);
}
@@ -428,7 +428,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
struct xkb_rule_names rules;
memset(&rules, 0, sizeof(rules));
struct input_config *input_config =
- keyboard->seat_device->input_device->config;
+ input_device_get_config(keyboard->seat_device->input_device);
struct wlr_input_device *wlr_device =
keyboard->seat_device->input_device->wlr_device;
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 9aa34aca..cf519a82 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -1,4 +1,5 @@
#define _XOPEN_SOURCE 700
+#include <assert.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_xcursor_manager.h>
@@ -25,7 +26,7 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
free(seat_device);
}
-void sway_seat_destroy(struct sway_seat *seat) {
+void seat_destroy(struct sway_seat *seat) {
struct sway_seat_device *seat_device, *next;
wl_list_for_each_safe(seat_device, next, &seat->devices, link) {
seat_device_destroy(seat_device);
@@ -35,30 +36,89 @@ void sway_seat_destroy(struct sway_seat *seat) {
wlr_seat_destroy(seat->wlr_seat);
}
+static struct sway_seat_container *seat_container_from_container(
+ struct sway_seat *seat, struct sway_container *con);
+
+static void seat_container_destroy(struct sway_seat_container *seat_con) {
+ struct sway_container *con = seat_con->container;
+ struct sway_container *child = NULL;
+
+ if (con->children != NULL) {
+ for (int i = 0; i < con->children->length; ++i) {
+ child = con->children->items[i];
+ struct sway_seat_container *seat_child =
+ seat_container_from_container(seat_con->seat, child);
+ seat_container_destroy(seat_child);
+ }
+ }
+
+ wl_list_remove(&seat_con->destroy.link);
+ wl_list_remove(&seat_con->link);
+ free(seat_con);
+}
+
+static void seat_send_focus(struct sway_seat *seat,
+ struct sway_container *con) {
+ if (con->type != C_VIEW) {
+ return;
+ }
+ struct sway_view *view = con->sway_view;
+ if (view->type == SWAY_XWAYLAND_VIEW) {
+ struct wlr_xwayland *xwayland =
+ seat->input->server->xwayland;
+ wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
+ }
+ view_set_activated(view, true);
+ struct wlr_keyboard *keyboard =
+ wlr_seat_get_keyboard(seat->wlr_seat);
+ if (keyboard) {
+ wlr_seat_keyboard_notify_enter(seat->wlr_seat,
+ view->surface, keyboard->keycodes,
+ keyboard->num_keycodes, &keyboard->modifiers);
+ } else {
+ wlr_seat_keyboard_notify_enter(
+ seat->wlr_seat, view->surface, NULL, 0, NULL);
+ }
+
+}
+
static void handle_seat_container_destroy(struct wl_listener *listener,
void *data) {
struct sway_seat_container *seat_con =
wl_container_of(listener, seat_con, destroy);
struct sway_seat *seat = seat_con->seat;
struct sway_container *con = seat_con->container;
+ struct sway_container *parent = con->parent;
+ struct sway_container *focus = seat_get_focus(seat);
- bool is_focus = (sway_seat_get_focus(seat) == con);
+ bool set_focus =
+ focus != NULL &&
+ (focus == con || container_has_child(con, focus)) &&
+ con->type != C_WORKSPACE;
- wl_list_remove(&seat_con->link);
+ seat_container_destroy(seat_con);
- if (is_focus) {
- // pick next focus
- sway_seat_set_focus(seat, NULL);
- struct sway_container *next = sway_seat_get_focus_inactive(seat, con->parent);
- if (next == NULL) {
- next = con->parent;
- }
- sway_seat_set_focus(seat, next);
- }
+ if (set_focus) {
+ struct sway_container *next_focus = NULL;
+ while (next_focus == NULL) {
+ next_focus = seat_get_focus_by_type(seat, parent, C_VIEW);
- wl_list_remove(&seat_con->destroy.link);
+ if (next_focus == NULL && parent->type == C_WORKSPACE) {
+ next_focus = parent;
+ break;
+ }
- free(seat_con);
+ parent = parent->parent;
+ }
+
+ // the structure change might have caused it to move up to the top of
+ // the focus stack without sending focus notifications to the view
+ if (seat_get_focus(seat) == next_focus) {
+ seat_send_focus(seat, next_focus);
+ } else {
+ seat_set_focus(seat, next_focus);
+ }
+ }
}
static struct sway_seat_container *seat_container_from_container(
@@ -110,7 +170,7 @@ static void collect_focus_iter(struct sway_container *con, void *data) {
wl_list_insert(&seat->focus_stack, &seat_con->link);
}
-struct sway_seat *sway_seat_create(struct sway_input_manager *input,
+struct sway_seat *seat_create(struct sway_input_manager *input,
const char *seat_name) {
struct sway_seat *seat = calloc(1, sizeof(struct sway_seat));
if (!seat) {
@@ -133,7 +193,8 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input,
// init the focus stack
wl_list_init(&seat->focus_stack);
- container_for_each_descendant_dfs(&root_container, collect_focus_iter, seat);
+ container_for_each_descendant_dfs(&root_container,
+ collect_focus_iter, seat);
wl_signal_add(&root_container.sway_root->events.new_container,
&seat->new_container);
@@ -147,7 +208,7 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input,
WL_SEAT_CAPABILITY_POINTER |
WL_SEAT_CAPABILITY_TOUCH);
- sway_seat_configure_xcursor(seat);
+ seat_configure_xcursor(seat);
wl_list_insert(&input->seats, &seat->link);
@@ -165,11 +226,12 @@ static void seat_configure_keyboard(struct sway_seat *seat,
if (!seat_device->keyboard) {
sway_keyboard_create(seat, seat_device);
}
- struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard;
+ struct wlr_keyboard *wlr_keyboard =
+ seat_device->input_device->wlr_device->keyboard;
sway_keyboard_configure(seat_device->keyboard);
wlr_seat_set_keyboard(seat->wlr_seat,
seat_device->input_device->wlr_device);
- struct sway_container *focus = sway_seat_get_focus(seat);
+ struct sway_container *focus = seat_get_focus(seat);
if (focus && focus->type == C_VIEW) {
// force notify reenter to pick up the new configuration
wlr_seat_keyboard_clear_focus(seat->wlr_seat);
@@ -179,7 +241,7 @@ static void seat_configure_keyboard(struct sway_seat *seat,
}
}
-static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat,
+static struct sway_seat_device *seat_get_device(struct sway_seat *seat,
struct sway_input_device *input_device) {
struct sway_seat_device *seat_device = NULL;
wl_list_for_each(seat_device, &seat->devices, link) {
@@ -191,19 +253,14 @@ static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat,
return NULL;
}
-void sway_seat_configure_device(struct sway_seat *seat,
+void seat_configure_device(struct sway_seat *seat,
struct sway_input_device *input_device) {
struct sway_seat_device *seat_device =
- sway_seat_get_device(seat, input_device);
+ seat_get_device(seat, input_device);
if (!seat_device) {
return;
}
- if (seat->config) {
- seat_device->attachment_config =
- seat_config_get_attachment(seat->config, input_device->identifier);
- }
-
switch (input_device->wlr_device->type) {
case WLR_INPUT_DEVICE_POINTER:
seat_configure_pointer(seat, seat_device);
@@ -219,10 +276,10 @@ void sway_seat_configure_device(struct sway_seat *seat,
}
}
-void sway_seat_add_device(struct sway_seat *seat,
+void seat_add_device(struct sway_seat *seat,
struct sway_input_device *input_device) {
- if (sway_seat_get_device(seat, input_device)) {
- sway_seat_configure_device(seat, input_device);
+ if (seat_get_device(seat, input_device)) {
+ seat_configure_device(seat, input_device);
return;
}
@@ -240,13 +297,13 @@ void sway_seat_add_device(struct sway_seat *seat,
seat_device->input_device = input_device;
wl_list_insert(&seat->devices, &seat_device->link);
- sway_seat_configure_device(seat, input_device);
+ seat_configure_device(seat, input_device);
}
-void sway_seat_remove_device(struct sway_seat *seat,
+void seat_remove_device(struct sway_seat *seat,
struct sway_input_device *input_device) {
struct sway_seat_device *seat_device =
- sway_seat_get_device(seat, input_device);
+ seat_get_device(seat, input_device);
if (!seat_device) {
return;
@@ -258,7 +315,7 @@ void sway_seat_remove_device(struct sway_seat *seat,
seat_device_destroy(seat_device);
}
-void sway_seat_configure_xcursor(struct sway_seat *seat) {
+void seat_configure_xcursor(struct sway_seat *seat) {
// TODO configure theme and size
const char *cursor_theme = NULL;
@@ -273,7 +330,8 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) {
}
for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output_container = root_container.children->items[i];
+ struct sway_container *output_container =
+ root_container.children->items[i];
struct wlr_output *output =
output_container->sway_output->wlr_output;
bool result =
@@ -292,10 +350,13 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) {
seat->cursor->cursor->y);
}
-void sway_seat_set_focus_warp(struct sway_seat *seat,
+void 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 (seat->focused_layer) {
+ return;
+ }
+ struct sway_container *last_focus = seat_get_focus(seat);
if (container && last_focus == container) {
return;
}
@@ -311,23 +372,7 @@ void sway_seat_set_focus_warp(struct sway_seat *seat,
wl_list_insert(&seat->focus_stack, &seat_con->link);
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) {
- wlr_seat_keyboard_notify_enter(seat->wlr_seat,
- view->surface, keyboard->keycodes,
- keyboard->num_keycodes, &keyboard->modifiers);
- } else {
- wlr_seat_keyboard_notify_enter(
- seat->wlr_seat, view->surface, NULL, 0, NULL);
- }
+ seat_send_focus(seat, container);
}
}
@@ -364,7 +409,7 @@ void sway_seat_set_focus_warp(struct sway_seat *seat,
}
if (last_focus && last_focus->type == C_VIEW &&
- !sway_input_manager_has_focus(seat->input, last_focus)) {
+ !input_manager_has_focus(seat->input, last_focus)) {
struct sway_view *view = last_focus->sway_view;
view_set_activated(view, false);
}
@@ -372,23 +417,69 @@ void sway_seat_set_focus_warp(struct sway_seat *seat,
seat->has_focus = (container != NULL);
}
-void sway_seat_set_focus(struct sway_seat *seat,
+void seat_set_focus(struct sway_seat *seat,
struct sway_container *container) {
- sway_seat_set_focus_warp(seat, container, true);
+ seat_set_focus_warp(seat, container, true);
}
-struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container) {
+void seat_set_focus_layer(struct sway_seat *seat,
+ struct wlr_layer_surface *layer) {
+ if (!layer) {
+ seat->focused_layer = NULL;
+ return;
+ }
+ if (seat->focused_layer == layer) {
+ return;
+ }
+ if (seat->has_focus) {
+ struct sway_container *focus = seat_get_focus(seat);
+ if (focus->type == C_VIEW) {
+ wlr_seat_keyboard_clear_focus(seat->wlr_seat);
+ view_set_activated(focus->sway_view, false);
+ }
+ }
+ if (layer->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
+ seat->focused_layer = layer;
+ }
+ struct wlr_keyboard *keyboard =
+ wlr_seat_get_keyboard(seat->wlr_seat);
+ if (keyboard) {
+ wlr_seat_keyboard_notify_enter(seat->wlr_seat,
+ layer->surface, keyboard->keycodes,
+ keyboard->num_keycodes, &keyboard->modifiers);
+ } else {
+ wlr_seat_keyboard_notify_enter(seat->wlr_seat,
+ layer->surface, NULL, 0, NULL);
+ }
+}
+
+struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
+ struct sway_container *container) {
+ return seat_get_focus_by_type(seat, container, C_TYPES);
+}
+
+struct sway_container *sway_seat_get_focus(struct sway_seat *seat) {
+ if (!seat->has_focus) {
+ return NULL;
+ }
+ return seat_get_focus_inactive(seat, &root_container);
+}
+
+struct sway_container *seat_get_focus_by_type(struct sway_seat *seat,
+ struct sway_container *container, enum sway_container_type type) {
struct sway_seat_container *current = NULL;
struct sway_container *parent = NULL;
wl_list_for_each(current, &seat->focus_stack, link) {
parent = current->container->parent;
- if (current->container == container) {
+ if (current->container == container &&
+ (type == C_TYPES || container->type == type)) {
return current->container;
}
while (parent) {
- if (parent == container) {
+ if (parent == container && (type == C_TYPES ||
+ current->container->type == type)) {
return current->container;
}
parent = parent->parent;
@@ -398,42 +489,34 @@ struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, stru
return NULL;
}
-struct sway_container *sway_seat_get_focus(struct sway_seat *seat) {
+struct sway_container *seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) {
return NULL;
}
- return sway_seat_get_focus_inactive(seat, &root_container);
+ return seat_get_focus_inactive(seat, &root_container);
}
-struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat,
- enum sway_container_type type) {
- struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container);
- if (focus->type == type) {
- return focus;
- }
-
- return container_parent(focus, type);
-}
-
-void sway_seat_set_config(struct sway_seat *seat,
+void seat_apply_config(struct sway_seat *seat,
struct seat_config *seat_config) {
- // clear configs
- free_seat_config(seat->config);
- seat->config = NULL;
-
struct sway_seat_device *seat_device = NULL;
- wl_list_for_each(seat_device, &seat->devices, link) {
- seat_device->attachment_config = NULL;
- }
if (!seat_config) {
return;
}
- // add configs
- seat->config = copy_seat_config(seat_config);
-
wl_list_for_each(seat_device, &seat->devices, link) {
- sway_seat_configure_device(seat, seat_device->input_device);
+ seat_configure_device(seat, seat_device->input_device);
}
}
+
+struct seat_config *seat_get_config(struct sway_seat *seat) {
+ struct seat_config *seat_config = NULL;
+ for (int i = 0; i < config->seat_configs->length; ++i ) {
+ seat_config = config->seat_configs->items[i];
+ if (strcmp(seat->wlr_seat->name, seat_config->name) == 0) {
+ return seat_config;
+ }
+ }
+
+ return NULL;
+}
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 7c5f7304..3427c8ec 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -88,11 +88,11 @@ static void ipc_json_describe_output(struct sway_container *container, json_obje
json_object_new_string(
ipc_json_get_output_transform(wlr_output->transform)));
- struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager);
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
const char *ws = NULL;
if (seat) {
struct sway_container *focus =
- sway_seat_get_focus_inactive(seat, container);
+ seat_get_focus_inactive(seat, container);
if (focus && focus->type != C_WORKSPACE) {
focus = container_parent(focus, C_WORKSPACE);
}
@@ -139,8 +139,8 @@ json_object *ipc_json_describe_container(struct sway_container *c) {
return NULL;
}
- struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager);
- bool focused = sway_seat_get_focus(seat) == c;
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
+ bool focused = seat_get_focus(seat) == c;
json_object *object = json_object_new_object();
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 869f1ed0..df5fb699 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -388,8 +388,8 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
// override the default focused indicator because
// it's set differently for the get_workspaces reply
struct sway_seat *seat =
- sway_input_manager_get_default_seat(input_manager);
- struct sway_container *focused_ws = sway_seat_get_focus(seat);
+ input_manager_get_default_seat(input_manager);
+ struct sway_container *focused_ws = seat_get_focus(seat);
if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) {
focused_ws = container_parent(focused_ws, C_WORKSPACE);
}
@@ -399,7 +399,7 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
json_object_new_boolean(focused));
json_object_array_add((json_object *)data, workspace_json);
- focused_ws = sway_seat_get_focus_inactive(seat, workspace->parent);
+ focused_ws = seat_get_focus_inactive(seat, workspace->parent);
if (focused_ws->type != C_WORKSPACE) {
focused_ws = container_parent(focused_ws, C_WORKSPACE);
}
diff --git a/sway/main.c b/sway/main.c
index ded922ee..e7f8ddd3 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -118,7 +118,7 @@ void run_as_ipc_client(char *command, char *socket_path) {
static void log_env() {
const char *log_vars[] = {
"PATH",
- "LD_LOAD_PATH",
+ "LD_LIBRARY_PATH",
"LD_PRELOAD_PATH",
"LD_LIBRARY_PATH",
"SWAY_CURSOR_THEME",
diff --git a/sway/meson.build b/sway/meson.build
index 0cc620ea..a6a633a0 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -19,6 +19,8 @@ sway_sources = files(
'commands/input.c',
'commands/layout.c',
'commands/mode.c',
+ 'commands/split.c',
+ 'commands/move.c',
'commands/seat.c',
'commands/seat/attach.c',
'commands/seat/fallback.c',
diff --git a/sway/server.c b/sway/server.c
index f5cc199c..54945312 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -109,7 +109,7 @@ bool server_init(struct sway_server *server) {
return false;
}
- input_manager = sway_input_manager_create(server);
+ input_manager = input_manager_create(server);
return true;
}
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 746dbf1f..4db93ce8 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -33,12 +33,29 @@ 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");
}
-static struct sway_container *container_create(enum sway_container_type type) {
+struct sway_container *container_create(enum sway_container_type type) {
// next id starts at 1 because 0 is assigned to root_container in layout.c
static size_t next_id = 1;
struct sway_container *c = calloc(1, sizeof(struct sway_container));
@@ -54,11 +71,12 @@ 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;
}
-struct sway_container *container_destroy(struct sway_container *cont) {
+static struct sway_container *_container_destroy(struct sway_container *cont) {
if (cont == NULL) {
return NULL;
}
@@ -66,13 +84,14 @@ struct sway_container *container_destroy(struct sway_container *cont) {
wl_signal_emit(&cont->events.destroy, cont);
struct sway_container *parent = cont->parent;
- if (cont->children) {
+ if (cont->children != NULL) {
// remove children until there are no more, container_destroy calls
// container_remove_child, which removes child from this container
- while (cont->children->length) {
- container_destroy(cont->children->items[0]);
+ while (cont->children != NULL && cont->children->length != 0) {
+ struct sway_container *child = cont->children->items[0];
+ container_remove_child(child);
+ container_destroy(child);
}
- list_free(cont->children);
}
if (cont->marks) {
list_foreach(cont->marks, free);
@@ -84,10 +103,19 @@ struct sway_container *container_destroy(struct sway_container *cont) {
if (cont->name) {
free(cont->name);
}
+ list_free(cont->children);
+ cont->children = NULL;
free(cont);
return parent;
}
+struct sway_container *container_destroy(struct sway_container *cont) {
+ struct sway_container *parent = _container_destroy(cont);
+ parent = container_reap_empty(parent);
+ arrange_windows(&root_container, -1, -1);
+ return parent;
+}
+
struct sway_container *container_output_create(
struct sway_output *sway_output) {
struct wlr_box size;
@@ -144,7 +172,7 @@ struct sway_container *container_output_create(
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input_manager->seats, link) {
if (!seat->has_focus) {
- sway_seat_set_focus(seat, ws);
+ seat_set_focus(seat, ws);
}
}
@@ -395,3 +423,17 @@ bool container_has_anscestor(struct sway_container *descendant,
}
return false;
}
+
+static bool find_child_func(struct sway_container *con, void *data) {
+ struct sway_container *child = data;
+ return con == child;
+}
+
+bool container_has_child(struct sway_container *con,
+ struct sway_container *child) {
+ if (child == NULL || child->type == C_VIEW ||
+ child->children->length == 0) {
+ return false;
+ }
+ return container_find(con, find_child_func, child);
+}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index ce0682dc..95a84d12 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
@@ -57,7 +58,7 @@ void layout_init(void) {
root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
root_container.sway_root->output_layout = wlr_output_layout_create();
- wl_list_init(&root_container.sway_root->unmanaged_views);
+ wl_list_init(&root_container.sway_root->xwayland_unmanaged);
wl_signal_init(&root_container.sway_root->events.new_container);
root_container.sway_root->output_layout_change.notify =
@@ -103,11 +104,13 @@ void container_add_child(struct sway_container *parent,
}
struct sway_container *container_reap_empty(struct sway_container *container) {
- if (!sway_assert(container, "reaping null container")) {
+ if (container == NULL) {
return NULL;
}
- wlr_log(L_DEBUG, "reaping %p %s", container, container->name);
- while (container != &root_container && 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;
@@ -135,25 +138,49 @@ struct sway_container *container_remove_child(struct sway_container *child) {
}
}
child->parent = NULL;
- return container_reap_empty(parent);
+ return 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 = 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);
+ seat_set_focus(seat, ws);
+ }
+ container_sort_workspaces(new_parent);
+ 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) {
@@ -248,8 +275,8 @@ void arrange_windows(struct sway_container *container,
struct wlr_box *area = &output->sway_output->usable_area;
wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
area->width, area->height, area->x, area->y);
- container->width = area->width;
- container->height = area->height;
+ container->width = width = area->width;
+ container->height = height = area->height;
container->x = x = area->x;
container->y = y = area->y;
wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
@@ -261,7 +288,7 @@ void arrange_windows(struct sway_container *container,
{
container->width = width;
container->height = height;
- view_set_size(container->sway_view,
+ view_configure(container->sway_view, container->x, container->y,
container->width, container->height);
wlr_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f",
container->width, container->height,
@@ -322,7 +349,14 @@ static void apply_horiz_layout(struct sway_container *container,
wlr_log(L_DEBUG,
"Calculating arrangement for %p:%d (will scale %f by %f)",
child, child->type, width, scale);
- view_set_position(child->sway_view, child_x, y);
+
+ if (child->type == C_VIEW) {
+ view_configure(child->sway_view, child_x, y, child->width,
+ child->height);
+ } else {
+ child->x = child_x;
+ child->y = y;
+ }
if (i == end - 1) {
double remaining_width = x + width - child_x;
@@ -373,7 +407,13 @@ void apply_vert_layout(struct sway_container *container,
wlr_log(L_DEBUG,
"Calculating arrangement for %p:%d (will scale %f by %f)",
child, child->type, height, scale);
- view_set_position(child->sway_view, x, child_y);
+ if (child->type == C_VIEW) {
+ view_configure(child->sway_view, x, child_y, child->width,
+ child->height);
+ } else {
+ child->x = x;
+ child->y = child_y;
+ }
if (i == end - 1) {
double remaining_height = y + height - child_y;
@@ -404,7 +444,7 @@ static struct sway_container *get_swayc_in_output_direction(
return NULL;
}
- struct sway_container *ws = sway_seat_get_focus_inactive(seat, output);
+ struct sway_container *ws = seat_get_focus_inactive(seat, output);
if (ws->type != C_WORKSPACE) {
ws = container_parent(ws, C_WORKSPACE);
}
@@ -425,7 +465,7 @@ static struct sway_container *get_swayc_in_output_direction(
case MOVE_UP:
case MOVE_DOWN: {
struct sway_container *focused =
- sway_seat_get_focus_inactive(seat, ws);
+ seat_get_focus_inactive(seat, ws);
if (focused && focused->parent) {
struct sway_container *parent = focused->parent;
if (parent->layout == L_VERT) {
@@ -505,11 +545,11 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) {
return NULL;
}
-static struct sway_container *get_swayc_in_direction_under(
- struct sway_container *container, enum movement_direction dir,
- struct sway_seat *seat, struct sway_container *limit) {
+struct sway_container *container_get_in_direction(
+ struct sway_container *container, struct sway_seat *seat,
+ enum movement_direction dir) {
if (dir == MOVE_CHILD) {
- return sway_seat_get_focus_inactive(seat, container);
+ return seat_get_focus_inactive(seat, container);
}
struct sway_container *parent = container->parent;
@@ -521,26 +561,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)) {
@@ -559,7 +579,6 @@ static struct sway_container *get_swayc_in_direction_under(
struct sway_container *wrap_candidate = NULL;
while (true) {
- // Test if we can even make a difference here
bool can_move = false;
int desired;
int idx = index_child(container);
@@ -589,7 +608,7 @@ static struct sway_container *get_swayc_in_direction_under(
}
if (next->children && next->children->length) {
// TODO consider floating children as well
- return sway_seat_get_focus_inactive(seat, next);
+ return seat_get_focus_by_type(seat, next, C_VIEW);
} else {
return next;
}
@@ -619,21 +638,23 @@ static struct sway_container *get_swayc_in_direction_under(
wrap_candidate = parent->children->items[0];
}
if (config->force_focus_wrapping) {
- return wrap_candidate;
+ return seat_get_focus_by_type(seat,
+ wrap_candidate, C_VIEW);
}
}
} else {
wlr_log(L_DEBUG,
"cont %d-%p dir %i sibling %d: %p", idx,
container, dir, desired, parent->children->items[desired]);
- return parent->children->items[desired];
+ return seat_get_focus_by_type(seat,
+ parent->children->items[desired], C_VIEW);
}
}
if (!can_move) {
container = parent;
parent = parent->parent;
- if (!parent || container == limit) {
+ if (!parent) {
// wrapping is the last chance
return wrap_candidate;
}
@@ -641,8 +662,70 @@ static struct sway_container *get_swayc_in_direction_under(
}
}
-struct sway_container *container_get_in_direction(
- struct sway_container *container, struct sway_seat *seat,
- enum movement_direction dir) {
- return get_swayc_in_direction_under(container, dir, seat, NULL);
+struct sway_container *container_replace_child(struct sway_container *child,
+ struct sway_container *new_child) {
+ struct sway_container *parent = child->parent;
+ if (parent == NULL) {
+ return NULL;
+ }
+ int i = index_child(child);
+
+ // TODO floating
+ parent->children->items[i] = new_child;
+ new_child->parent = parent;
+ child->parent = NULL;
+
+ // Set geometry for new child
+ new_child->x = child->x;
+ new_child->y = child->y;
+ new_child->width = child->width;
+ new_child->height = child->height;
+
+ // reset geometry for child
+ child->width = 0;
+ child->height = 0;
+
+ return parent;
+}
+
+struct sway_container *container_split(struct sway_container *child,
+ enum sway_container_layout layout) {
+ // TODO floating: cannot split a floating container
+ if (!sway_assert(child, "child cannot be null")) {
+ return NULL;
+ }
+ struct sway_container *cont = container_create(C_CONTAINER);
+
+ wlr_log(L_DEBUG, "creating container %p around %p", cont, child);
+
+ cont->prev_layout = L_NONE;
+ cont->width = child->width;
+ cont->height = child->height;
+ cont->x = child->x;
+ cont->y = child->y;
+
+ if (child->type == C_WORKSPACE) {
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
+ struct sway_container *workspace = child;
+ bool set_focus = (seat_get_focus(seat) == workspace);
+
+ while (workspace->children->length) {
+ struct sway_container *ws_child = workspace->children->items[0];
+ container_remove_child(ws_child);
+ container_add_child(cont, ws_child);
+ }
+
+ container_add_child(workspace, cont);
+ container_set_layout(workspace, layout);
+
+ if (set_focus) {
+ seat_set_focus(seat, cont);
+ }
+ } else {
+ cont->layout = layout;
+ container_replace_child(child, cont);
+ container_add_child(cont, child);
+ }
+
+ return cont;
}
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 7248fd00..0509db23 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"
@@ -29,6 +30,7 @@ struct sway_container *container_output_destroy(struct sway_container *output) {
wl_list_remove(&output->sway_output->destroy.link);
wl_list_remove(&output->sway_output->mode.link);
wl_list_remove(&output->sway_output->transform.link);
+ wl_list_remove(&output->sway_output->scale.link);
wl_list_remove(&output->sway_output->damage_destroy.link);
wl_list_remove(&output->sway_output->damage_frame.link);
@@ -37,3 +39,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;
+}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index b7d1a41b..09c804e4 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <wayland-server.h>
#include <wlr/types/wlr_output_layout.h>
#include "log.h"
@@ -6,82 +7,117 @@
#include "sway/tree/layout.h"
#include "sway/tree/view.h"
+struct sway_view *view_create(enum sway_view_type type,
+ const struct sway_view_impl *impl) {
+ struct sway_view *view = calloc(1, sizeof(struct sway_view));
+ if (view == NULL) {
+ return NULL;
+ }
+ view->type = type;
+ view->impl = impl;
+ return view;
+}
+
+void view_destroy(struct sway_view *view) {
+ if (view == NULL) {
+ return;
+ }
+
+ if (view->surface != NULL) {
+ view_unmap(view);
+ }
+
+ container_view_destroy(view->swayc);
+ free(view);
+}
+
const char *view_get_title(struct sway_view *view) {
- if (view->iface.get_prop) {
- return view->iface.get_prop(view, VIEW_PROP_TITLE);
+ if (view->impl->get_prop) {
+ return view->impl->get_prop(view, VIEW_PROP_TITLE);
}
return NULL;
}
const char *view_get_app_id(struct sway_view *view) {
- if (view->iface.get_prop) {
- return view->iface.get_prop(view, VIEW_PROP_APP_ID);
+ if (view->impl->get_prop) {
+ return view->impl->get_prop(view, VIEW_PROP_APP_ID);
}
return NULL;
}
const char *view_get_class(struct sway_view *view) {
- if (view->iface.get_prop) {
- return view->iface.get_prop(view, VIEW_PROP_CLASS);
+ if (view->impl->get_prop) {
+ return view->impl->get_prop(view, VIEW_PROP_CLASS);
}
return NULL;
}
const char *view_get_instance(struct sway_view *view) {
- if (view->iface.get_prop) {
- return view->iface.get_prop(view, VIEW_PROP_INSTANCE);
+ if (view->impl->get_prop) {
+ return view->impl->get_prop(view, VIEW_PROP_INSTANCE);
}
return NULL;
}
-void view_set_size(struct sway_view *view, int width, int height) {
- if (view->iface.set_size) {
- struct wlr_box box = {
- .x = view->swayc->x,
- .y = view->swayc->y,
- .width = view->width,
- .height = view->height,
- };
- view->iface.set_size(view, width, height);
- view_update_outputs(view, &box);
+void view_configure(struct sway_view *view, double ox, double oy, int width,
+ int height) {
+ if (view->impl->configure) {
+ view->impl->configure(view, ox, oy, width, height);
}
}
-// TODO make view coordinates in layout coordinates
-void view_set_position(struct sway_view *view, double ox, double oy) {
- if (view->iface.set_position) {
- struct wlr_box box = {
- .x = view->swayc->x,
- .y = view->swayc->y,
- .width = view->width,
- .height = view->height,
- };
- view->iface.set_position(view, ox, oy);
- view_update_outputs(view, &box);
+void view_set_activated(struct sway_view *view, bool activated) {
+ if (view->impl->set_activated) {
+ view->impl->set_activated(view, activated);
}
}
-void view_set_activated(struct sway_view *view, bool activated) {
- if (view->iface.set_activated) {
- view->iface.set_activated(view, activated);
+void view_close(struct sway_view *view) {
+ if (view->impl->close) {
+ view->impl->close(view);
}
}
-void view_close(struct sway_view *view) {
- if (view->iface.close) {
- view->iface.close(view);
+struct sway_container *container_view_destroy(struct sway_container *view) {
+ if (!view) {
+ return NULL;
}
+ wlr_log(L_DEBUG, "Destroying view '%s'", view->name);
+ struct sway_container *parent = container_destroy(view);
+ arrange_windows(parent, -1, -1);
+ return parent;
+}
+
+void view_damage_whole(struct sway_view *view) {
+ for (int i = 0; i < root_container.children->length; ++i) {
+ struct sway_container *cont = root_container.children->items[i];
+ if (cont->type == C_OUTPUT) {
+ output_damage_whole_view(cont->sway_output, view);
+ }
+ }
+}
+
+void view_damage_from(struct sway_view *view) {
+ // TODO
+ view_damage_whole(view);
+}
+
+static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) {
+ struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
+
+ box->x = output->x + view->swayc->x;
+ box->y = output->y + view->swayc->y;
+ box->width = view->width;
+ box->height = view->height;
}
-void view_update_outputs(struct sway_view *view, const struct wlr_box *before) {
+static void view_update_outputs(struct sway_view *view,
+ const struct wlr_box *before) {
+ struct wlr_box box;
+ view_get_layout_box(view, &box);
+
struct wlr_output_layout *output_layout =
root_container.sway_root->output_layout;
- struct wlr_box box = {
- .x = view->swayc->x,
- .y = view->swayc->y,
- .width = view->width,
- .height = view->height,
- };
struct wlr_output_layout_output *layout_output;
wl_list_for_each(layout_output, &output_layout->outputs, link) {
bool intersected = before != NULL && wlr_output_layout_intersects(
@@ -97,27 +133,63 @@ void view_update_outputs(struct sway_view *view, const struct wlr_box *before) {
}
}
-struct sway_container *container_view_destroy(struct sway_container *view) {
- if (!view) {
- return NULL;
+void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
+ if (!sway_assert(view->surface == NULL, "cannot map mapped view")) {
+ return;
}
- wlr_log(L_DEBUG, "Destroying view '%s'", view->name);
- struct sway_container *parent = container_destroy(view);
- arrange_windows(parent, -1, -1);
- return parent;
+
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ struct sway_container *focus = seat_get_focus_inactive(seat,
+ &root_container);
+ struct sway_container *cont = container_view_create(focus, view);
+
+ view->surface = wlr_surface;
+ view->swayc = cont;
+
+ arrange_windows(cont->parent, -1, -1);
+ input_manager_set_focus(input_manager, cont);
+
+ view_damage_whole(view);
+ view_update_outputs(view, NULL);
}
-void view_damage_whole(struct sway_view *view) {
- struct sway_container *cont = NULL;
- for (int i = 0; i < root_container.children->length; ++i) {
- cont = root_container.children->items[i];
- if (cont->type == C_OUTPUT) {
- output_damage_whole_view(cont->sway_output, view);
- }
+void view_unmap(struct sway_view *view) {
+ if (!sway_assert(view->surface != NULL, "cannot unmap unmapped view")) {
+ return;
}
+
+ view_damage_whole(view);
+
+ container_view_destroy(view->swayc);
+
+ view->swayc = NULL;
+ view->surface = NULL;
}
-void view_damage_from(struct sway_view *view) {
- // TODO
+void view_update_position(struct sway_view *view, double ox, double oy) {
+ if (view->swayc->x == ox && view->swayc->y == oy) {
+ return;
+ }
+
+ struct wlr_box box;
+ view_get_layout_box(view, &box);
+ view_damage_whole(view);
+ view->swayc->x = ox;
+ view->swayc->y = oy;
+ view_update_outputs(view, &box);
+ view_damage_whole(view);
+}
+
+void view_update_size(struct sway_view *view, int width, int height) {
+ if (view->width == width && view->height == height) {
+ return;
+ }
+
+ struct wlr_box box;
+ view_get_layout_box(view, &box);
+ view_damage_whole(view);
+ view->width = width;
+ view->height = height;
+ view_update_outputs(view, &box);
view_damage_whole(view);
}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index d6fd7c70..8077de2e 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -176,7 +176,7 @@ static bool _workspace_by_name(struct sway_container *view, void *data) {
struct sway_container *workspace_by_name(const char *name) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *current_workspace = NULL, *current_output = NULL;
- struct sway_container *focus = sway_seat_get_focus(seat);
+ struct sway_container *focus = seat_get_focus(seat);
if (focus) {
current_workspace = container_parent(focus, C_WORKSPACE);
current_output = container_parent(focus, C_OUTPUT);
@@ -218,7 +218,7 @@ struct sway_container *workspace_create(const char *name) {
// Otherwise create a new one
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus =
- sway_seat_get_focus_inactive(seat, &root_container);
+ seat_get_focus_inactive(seat, &root_container);
parent = focus;
parent = container_parent(parent, C_OUTPUT);
struct sway_container *new_ws = container_workspace_create(parent, name);
@@ -278,7 +278,7 @@ struct sway_container *workspace_output_prev_next_impl(
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = sway_seat_get_focus_inactive(seat, output);
+ struct sway_container *focus = seat_get_focus_inactive(seat, output);
struct sway_container *workspace = (focus->type == C_WORKSPACE ?
focus :
container_parent(focus, C_WORKSPACE));
@@ -363,13 +363,13 @@ bool workspace_switch(struct sway_container *workspace) {
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus =
- sway_seat_get_focus_inactive(seat, &root_container);
+ seat_get_focus_inactive(seat, &root_container);
if (!seat || !focus) {
return false;
}
struct sway_container *active_ws = focus;
if (active_ws->type != C_WORKSPACE) {
- container_parent(focus, C_WORKSPACE);
+ active_ws = container_parent(focus, C_WORKSPACE);
}
if (config->auto_back_and_forth
@@ -394,11 +394,11 @@ bool workspace_switch(struct sway_container *workspace) {
wlr_log(L_DEBUG, "Switching to workspace %p:%s",
workspace, workspace->name);
- struct sway_container *next = sway_seat_get_focus_inactive(seat, workspace);
+ struct sway_container *next = seat_get_focus_inactive(seat, workspace);
if (next == NULL) {
next = workspace;
}
- sway_seat_set_focus(seat, next);
+ seat_set_focus(seat, next);
struct sway_container *output = container_parent(workspace, C_OUTPUT);
arrange_windows(output, -1, -1);
return true;
@@ -407,7 +407,7 @@ bool workspace_switch(struct sway_container *workspace) {
bool workspace_is_visible(struct sway_container *ws) {
struct sway_container *output = container_parent(ws, C_OUTPUT);
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = sway_seat_get_focus_inactive(seat, output);
+ struct sway_container *focus = seat_get_focus_inactive(seat, output);
if (focus->type != C_WORKSPACE) {
focus = container_parent(focus, C_WORKSPACE);
}