aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/container.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-19 11:01:51 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-20 09:23:24 +1000
commit0f6d212629964c6a131b5675fa6c9f4d48da43aa (patch)
tree2dec4ff1e44ede939eb01927425c5da61e41ab5e /sway/tree/container.c
parentMerge pull request #2493 from RyanDwyer/fix-popup-position (diff)
downloadsway-0f6d212629964c6a131b5675fa6c9f4d48da43aa.tar.gz
sway-0f6d212629964c6a131b5675fa6c9f4d48da43aa.tar.zst
sway-0f6d212629964c6a131b5675fa6c9f4d48da43aa.zip
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) {
76 } 76 }
77} 77}
78 78
79static void handle_reparent(struct wl_listener *listener,
80 void *data) {
81 struct sway_container *container =
82 wl_container_of(listener, container, reparent);
83 struct sway_container *old_parent = data;
84
85 struct sway_container *old_output = old_parent;
86 if (old_output != NULL && old_output->type != C_OUTPUT) {
87 old_output = container_parent(old_output, C_OUTPUT);
88 }
89
90 struct sway_container *new_output = container->parent;
91 if (new_output != NULL && new_output->type != C_OUTPUT) {
92 new_output = container_parent(new_output, C_OUTPUT);
93 }
94
95 if (old_output && new_output) {
96 float old_scale = old_output->sway_output->wlr_output->scale;
97 float new_scale = new_output->sway_output->wlr_output->scale;
98 if (old_scale != new_scale) {
99 container_update_textures_recursive(container);
100 }
101 }
102}
103
104struct sway_container *container_create(enum sway_container_type type) { 79struct sway_container *container_create(enum sway_container_type type) {
105 // next id starts at 1 because 0 is assigned to root_container in layout.c 80 // next id starts at 1 because 0 is assigned to root_container in layout.c
106 static size_t next_id = 1; 81 static size_t next_id = 1;
@@ -117,12 +92,9 @@ struct sway_container *container_create(enum sway_container_type type) {
117 c->children = create_list(); 92 c->children = create_list();
118 c->current.children = create_list(); 93 c->current.children = create_list();
119 } 94 }
95 c->outputs = create_list();
120 96
121 wl_signal_init(&c->events.destroy); 97 wl_signal_init(&c->events.destroy);
122 wl_signal_init(&c->events.reparent);
123
124 wl_signal_add(&c->events.reparent, &c->reparent);
125 c->reparent.notify = handle_reparent;
126 98
127 c->has_gaps = false; 99 c->has_gaps = false;
128 c->gaps_inner = 0; 100 c->gaps_inner = 0;
@@ -156,6 +128,7 @@ void container_free(struct sway_container *cont) {
156 wlr_texture_destroy(cont->title_urgent); 128 wlr_texture_destroy(cont->title_urgent);
157 list_free(cont->children); 129 list_free(cont->children);
158 list_free(cont->current.children); 130 list_free(cont->current.children);
131 list_free(cont->outputs);
159 132
160 switch (cont->type) { 133 switch (cont->type) {
161 case C_ROOT: 134 case C_ROOT:
@@ -777,13 +750,25 @@ void container_damage_whole(struct sway_container *container) {
777 } 750 }
778} 751}
779 752
753/**
754 * Return the output which will be used for scale purposes.
755 * This is the most recently entered output.
756 */
757static struct sway_output *container_get_effective_output(
758 struct sway_container *con) {
759 if (con->outputs->length == 0) {
760 return NULL;
761 }
762 return con->outputs->items[con->outputs->length - 1];
763}
764
780static void update_title_texture(struct sway_container *con, 765static void update_title_texture(struct sway_container *con,
781 struct wlr_texture **texture, struct border_colors *class) { 766 struct wlr_texture **texture, struct border_colors *class) {
782 if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, 767 if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
783 "Unexpected type %s", container_type_to_str(con->type))) { 768 "Unexpected type %s", container_type_to_str(con->type))) {
784 return; 769 return;
785 } 770 }
786 struct sway_container *output = container_parent(con, C_OUTPUT); 771 struct sway_output *output = container_get_effective_output(con);
787 if (!output) { 772 if (!output) {
788 return; 773 return;
789 } 774 }
@@ -795,7 +780,7 @@ static void update_title_texture(struct sway_container *con,
795 return; 780 return;
796 } 781 }
797 782
798 double scale = output->sway_output->wlr_output->scale; 783 double scale = output->wlr_output->scale;
799 int width = 0; 784 int width = 0;
800 int height = con->title_height * scale; 785 int height = con->title_height * scale;
801 786
@@ -823,7 +808,7 @@ static void update_title_texture(struct sway_container *con,
823 unsigned char *data = cairo_image_surface_get_data(surface); 808 unsigned char *data = cairo_image_surface_get_data(surface);
824 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); 809 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
825 struct wlr_renderer *renderer = wlr_backend_get_renderer( 810 struct wlr_renderer *renderer = wlr_backend_get_renderer(
826 output->sway_output->wlr_output->backend); 811 output->wlr_output->backend);
827 *texture = wlr_texture_from_pixels( 812 *texture = wlr_texture_from_pixels(
828 renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); 813 renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data);
829 cairo_surface_destroy(surface); 814 cairo_surface_destroy(surface);
@@ -1272,3 +1257,67 @@ bool container_is_fullscreen_or_child(struct sway_container *container) {
1272 1257
1273 return false; 1258 return false;
1274} 1259}
1260
1261static void surface_send_enter_iterator(struct wlr_surface *surface,
1262 int x, int y, void *data) {
1263 struct wlr_output *wlr_output = data;
1264 wlr_surface_send_enter(surface, wlr_output);
1265}
1266
1267static void surface_send_leave_iterator(struct wlr_surface *surface,
1268 int x, int y, void *data) {
1269 struct wlr_output *wlr_output = data;
1270 wlr_surface_send_leave(surface, wlr_output);
1271}
1272
1273void container_discover_outputs(struct sway_container *con) {
1274 if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
1275 "Expected a container or view")) {
1276 return;
1277 }
1278 struct wlr_box con_box = {
1279 .x = con->current.swayc_x,
1280 .y = con->current.swayc_y,
1281 .width = con->current.swayc_width,
1282 .height = con->current.swayc_height,
1283 };
1284 struct sway_output *old_output = container_get_effective_output(con);
1285
1286 for (int i = 0; i < root_container.children->length; ++i) {
1287 struct sway_container *output = root_container.children->items[i];
1288 struct sway_output *sway_output = output->sway_output;
1289 struct wlr_box output_box;
1290 container_get_box(output, &output_box);
1291 struct wlr_box intersection;
1292 bool intersects =
1293 wlr_box_intersection(&con_box, &output_box, &intersection);
1294 int index = list_find(con->outputs, sway_output);
1295
1296 if (intersects && index == -1) {
1297 // Send enter
1298 wlr_log(WLR_DEBUG, "Con %p entered output %p", con, sway_output);
1299 if (con->type == C_VIEW) {
1300 view_for_each_surface(con->sway_view,
1301 surface_send_enter_iterator, sway_output->wlr_output);
1302 }
1303 list_add(con->outputs, sway_output);
1304 } else if (!intersects && index != -1) {
1305 // Send leave
1306 wlr_log(WLR_DEBUG, "Con %p left output %p", con, sway_output);
1307 if (con->type == C_VIEW) {
1308 view_for_each_surface(con->sway_view,
1309 surface_send_leave_iterator, sway_output->wlr_output);
1310 }
1311 list_del(con->outputs, index);
1312 }
1313 }
1314 struct sway_output *new_output = container_get_effective_output(con);
1315 double old_scale = old_output ? old_output->wlr_output->scale : -1;
1316 double new_scale = new_output ? new_output->wlr_output->scale : -1;
1317 if (old_scale != new_scale) {
1318 container_update_title_textures(con);
1319 if (con->type == C_VIEW) {
1320 view_update_marks_textures(con->sway_view);
1321 }
1322 }
1323}