aboutsummaryrefslogtreecommitdiff
path: root/sway/tree/container.c
diff options
context:
space:
mode:
authorRyan Dwyer <ryandwyer1@gmail.com>2018-08-19 11:01:51 +1000
committerRyan Dwyer <ryandwyer1@gmail.com>2018-08-20 09:23:24 +1000
commit0f6d212629964c6a131b5675fa6c9f4d48da43aa (patch)
tree2dec4ff1e44ede939eb01927425c5da61e41ab5e /sway/tree/container.c
parent8db6c68db640e8535ed71a0369323538f0910d7e (diff)
Send output enter/leave events correctly
Previously we used a reparent event to detect when a view changes parent, then sent an output enter/leave to the surfaces if needed. This worked for tiling views but not floating views, as floating views can intersect another output without changing parent. The solution implemented for floating views also applies cleanly to tiling views, so the previous method has been completely replaced and the reparent event has been removed. This introduces a new function container_discover_outputs. This function compares the container's `current` position to the outputs, sends enter and leave events as needed, and keeps track of which outputs it's intersecting in a new `container->outputs` list. If it has entered a new output with a different scale then the title and marks textures will also be recreated at the new scale. The function is called when a transaction applies. This is convenient as it means we don't have to call it from various places. There is imperfect rendering when a floating view overlaps two outputs with different scales. It renders correctly for the most recently entered output, but there is only one title texture so it renders incorrectly on the old output. Fixes #2482
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r--sway/tree/container.c113
1 files changed, 81 insertions, 32 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c
index ea20991c..80d3f524 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -76,31 +76,6 @@ void container_update_textures_recursive(struct sway_container *con) {
}
}
-static void handle_reparent(struct wl_listener *listener,
- void *data) {
- struct sway_container *container =
- wl_container_of(listener, container, reparent);
- struct sway_container *old_parent = data;
-
- struct sway_container *old_output = old_parent;
- if (old_output != NULL && old_output->type != C_OUTPUT) {
- old_output = container_parent(old_output, C_OUTPUT);
- }
-
- struct sway_container *new_output = container->parent;
- if (new_output != NULL && new_output->type != C_OUTPUT) {
- new_output = container_parent(new_output, C_OUTPUT);
- }
-
- if (old_output && new_output) {
- float old_scale = old_output->sway_output->wlr_output->scale;
- float new_scale = new_output->sway_output->wlr_output->scale;
- if (old_scale != new_scale) {
- container_update_textures_recursive(container);
- }
- }
-}
-
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;
@@ -117,12 +92,9 @@ struct sway_container *container_create(enum sway_container_type type) {
c->children = create_list();
c->current.children = create_list();
}
+ c->outputs = create_list();
wl_signal_init(&c->events.destroy);
- wl_signal_init(&c->events.reparent);
-
- wl_signal_add(&c->events.reparent, &c->reparent);
- c->reparent.notify = handle_reparent;
c->has_gaps = false;
c->gaps_inner = 0;
@@ -156,6 +128,7 @@ void container_free(struct sway_container *cont) {
wlr_texture_destroy(cont->title_urgent);
list_free(cont->children);
list_free(cont->current.children);
+ list_free(cont->outputs);
switch (cont->type) {
case C_ROOT:
@@ -777,13 +750,25 @@ void container_damage_whole(struct sway_container *container) {
}
}
+/**
+ * Return the output which will be used for scale purposes.
+ * This is the most recently entered output.
+ */
+static struct sway_output *container_get_effective_output(
+ struct sway_container *con) {
+ if (con->outputs->length == 0) {
+ return NULL;
+ }
+ return con->outputs->items[con->outputs->length - 1];
+}
+
static void update_title_texture(struct sway_container *con,
struct wlr_texture **texture, struct border_colors *class) {
if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
"Unexpected type %s", container_type_to_str(con->type))) {
return;
}
- struct sway_container *output = container_parent(con, C_OUTPUT);
+ struct sway_output *output = container_get_effective_output(con);
if (!output) {
return;
}
@@ -795,7 +780,7 @@ static void update_title_texture(struct sway_container *con,
return;
}
- double scale = output->sway_output->wlr_output->scale;
+ double scale = output->wlr_output->scale;
int width = 0;
int height = con->title_height * scale;
@@ -823,7 +808,7 @@ static void update_title_texture(struct sway_container *con,
unsigned char *data = cairo_image_surface_get_data(surface);
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
struct wlr_renderer *renderer = wlr_backend_get_renderer(
- output->sway_output->wlr_output->backend);
+ output->wlr_output->backend);
*texture = wlr_texture_from_pixels(
renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data);
cairo_surface_destroy(surface);
@@ -1272,3 +1257,67 @@ bool container_is_fullscreen_or_child(struct sway_container *container) {
return false;
}
+
+static void surface_send_enter_iterator(struct wlr_surface *surface,
+ int x, int y, void *data) {
+ struct wlr_output *wlr_output = data;
+ wlr_surface_send_enter(surface, wlr_output);
+}
+
+static void surface_send_leave_iterator(struct wlr_surface *surface,
+ int x, int y, void *data) {
+ struct wlr_output *wlr_output = data;
+ wlr_surface_send_leave(surface, wlr_output);
+}
+
+void container_discover_outputs(struct sway_container *con) {
+ if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
+ "Expected a container or view")) {
+ return;
+ }
+ struct wlr_box con_box = {
+ .x = con->current.swayc_x,
+ .y = con->current.swayc_y,
+ .width = con->current.swayc_width,
+ .height = con->current.swayc_height,
+ };
+ struct sway_output *old_output = container_get_effective_output(con);
+
+ for (int i = 0; i < root_container.children->length; ++i) {
+ struct sway_container *output = root_container.children->items[i];
+ struct sway_output *sway_output = output->sway_output;
+ struct wlr_box output_box;
+ container_get_box(output, &output_box);
+ struct wlr_box intersection;
+ bool intersects =
+ wlr_box_intersection(&con_box, &output_box, &intersection);
+ int index = list_find(con->outputs, sway_output);
+
+ if (intersects && index == -1) {
+ // Send enter
+ wlr_log(WLR_DEBUG, "Con %p entered output %p", con, sway_output);
+ if (con->type == C_VIEW) {
+ view_for_each_surface(con->sway_view,
+ surface_send_enter_iterator, sway_output->wlr_output);
+ }
+ list_add(con->outputs, sway_output);
+ } else if (!intersects && index != -1) {
+ // Send leave
+ wlr_log(WLR_DEBUG, "Con %p left output %p", con, sway_output);
+ if (con->type == C_VIEW) {
+ view_for_each_surface(con->sway_view,
+ surface_send_leave_iterator, sway_output->wlr_output);
+ }
+ list_del(con->outputs, index);
+ }
+ }
+ struct sway_output *new_output = container_get_effective_output(con);
+ double old_scale = old_output ? old_output->wlr_output->scale : -1;
+ double new_scale = new_output ? new_output->wlr_output->scale : -1;
+ if (old_scale != new_scale) {
+ container_update_title_textures(con);
+ if (con->type == C_VIEW) {
+ view_update_marks_textures(con->sway_view);
+ }
+ }
+}