aboutsummaryrefslogtreecommitdiffstats
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
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
-rw-r--r--include/sway/tree/container.h10
-rw-r--r--include/sway/tree/view.h1
-rw-r--r--sway/commands/move.c1
-rw-r--r--sway/desktop/transaction.c3
-rw-r--r--sway/tree/container.c113
-rw-r--r--sway/tree/layout.c8
-rw-r--r--sway/tree/view.c58
7 files changed, 93 insertions, 101 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 5eccedc1..e0cda17c 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -138,6 +138,9 @@ struct sway_container {
138 138
139 struct sway_container *parent; 139 struct sway_container *parent;
140 140
141 // Outputs currently being intersected
142 list_t *outputs; // struct sway_output
143
141 // Indicates that the container is a scratchpad container. 144 // Indicates that the container is a scratchpad container.
142 // Both hidden and visible scratchpad containers have scratchpad=true. 145 // Both hidden and visible scratchpad containers have scratchpad=true.
143 // Hidden scratchpad containers have a NULL parent. 146 // Hidden scratchpad containers have a NULL parent.
@@ -166,12 +169,7 @@ struct sway_container {
166 169
167 struct { 170 struct {
168 struct wl_signal destroy; 171 struct wl_signal destroy;
169 // Raised after the tree updates, but before arrange_windows
170 // Passed the previous parent
171 struct wl_signal reparent;
172 } events; 172 } events;
173
174 struct wl_listener reparent;
175}; 173};
176 174
177struct sway_container *container_create(enum sway_container_type type); 175struct sway_container *container_create(enum sway_container_type type);
@@ -353,4 +351,6 @@ bool container_is_floating_or_child(struct sway_container *container);
353 */ 351 */
354bool container_is_fullscreen_or_child(struct sway_container *container); 352bool container_is_fullscreen_or_child(struct sway_container *container);
355 353
354void container_discover_outputs(struct sway_container *con);
355
356#endif 356#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 2747e7c4..5fdecc2b 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -120,7 +120,6 @@ struct sway_view {
120 } events; 120 } events;
121 121
122 struct wl_listener surface_new_subsurface; 122 struct wl_listener surface_new_subsurface;
123 struct wl_listener container_reparent;
124}; 123};
125 124
126struct sway_xdg_shell_v6_view { 125struct sway_xdg_shell_v6_view {
diff --git a/sway/commands/move.c b/sway/commands/move.c
index e788d32f..c6dc0775 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -236,7 +236,6 @@ static void workspace_move_to_output(struct sway_container *workspace,
236 seat_get_focus_inactive(seat, output); 236 seat_get_focus_inactive(seat, output);
237 237
238 container_add_child(output, workspace); 238 container_add_child(output, workspace);
239 wl_signal_emit(&workspace->events.reparent, old_output);
240 239
241 // If moving the last workspace from the old output, create a new workspace 240 // If moving the last workspace from the old output, create a new workspace
242 // on the old output 241 // on the old output
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index d77a2afd..53ecc1f0 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -193,6 +193,9 @@ static void transaction_apply(struct sway_transaction *transaction) {
193 } 193 }
194 194
195 container->instruction = NULL; 195 container->instruction = NULL;
196 if (container->type == C_CONTAINER || container->type == C_VIEW) {
197 container_discover_outputs(container);
198 }
196 } 199 }
197} 200}
198 201
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}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 2f22a3dd..ee7d7418 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -75,7 +75,6 @@ void container_insert_child(struct sway_container *parent,
75 list_insert(parent->children, i, child); 75 list_insert(parent->children, i, child);
76 child->parent = parent; 76 child->parent = parent;
77 container_handle_fullscreen_reparent(child, old_parent); 77 container_handle_fullscreen_reparent(child, old_parent);
78 wl_signal_emit(&child->events.reparent, old_parent);
79} 78}
80 79
81struct sway_container *container_add_sibling(struct sway_container *fixed, 80struct sway_container *container_add_sibling(struct sway_container *fixed,
@@ -91,7 +90,6 @@ struct sway_container *container_add_sibling(struct sway_container *fixed,
91 list_insert(parent->children, i + 1, active); 90 list_insert(parent->children, i + 1, active);
92 active->parent = parent; 91 active->parent = parent;
93 container_handle_fullscreen_reparent(active, old_parent); 92 container_handle_fullscreen_reparent(active, old_parent);
94 wl_signal_emit(&active->events.reparent, old_parent);
95 return active->parent; 93 return active->parent;
96} 94}
97 95
@@ -181,8 +179,6 @@ void container_move_to(struct sway_container *container,
181 } 179 }
182 } 180 }
183 181
184 wl_signal_emit(&container->events.reparent, old_parent);
185
186 if (container->type == C_VIEW) { 182 if (container->type == C_VIEW) {
187 ipc_event_window(container, "move"); 183 ipc_event_window(container, "move");
188 } 184 }
@@ -307,7 +303,6 @@ static void workspace_rejigger(struct sway_container *ws,
307 303
308 container_flatten(ws); 304 container_flatten(ws);
309 container_reap_empty_recursive(original_parent); 305 container_reap_empty_recursive(original_parent);
310 wl_signal_emit(&child->events.reparent, original_parent);
311 container_create_notify(new_parent); 306 container_create_notify(new_parent);
312} 307}
313 308
@@ -859,7 +854,6 @@ struct sway_container *container_split(struct sway_container *child,
859 struct sway_container *ws_child = workspace->children->items[0]; 854 struct sway_container *ws_child = workspace->children->items[0];
860 container_remove_child(ws_child); 855 container_remove_child(ws_child);
861 container_add_child(cont, ws_child); 856 container_add_child(cont, ws_child);
862 wl_signal_emit(&ws_child->events.reparent, workspace);
863 } 857 }
864 858
865 container_add_child(workspace, cont); 859 container_add_child(workspace, cont);
@@ -867,11 +861,9 @@ struct sway_container *container_split(struct sway_container *child,
867 workspace->layout = layout; 861 workspace->layout = layout;
868 cont->layout = old_layout; 862 cont->layout = old_layout;
869 } else { 863 } else {
870 struct sway_container *old_parent = child->parent;
871 cont->layout = layout; 864 cont->layout = layout;
872 container_replace_child(child, cont); 865 container_replace_child(child, cont);
873 container_add_child(cont, child); 866 container_add_child(cont, child);
874 wl_signal_emit(&child->events.reparent, old_parent);
875 } 867 }
876 868
877 if (set_focus) { 869 if (set_focus) {
diff --git a/sway/tree/view.c b/sway/tree/view.c
index b77a9bb2..4abf1abb 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -364,48 +364,6 @@ static void view_handle_surface_new_subsurface(struct wl_listener *listener,
364 view_subsurface_create(view, subsurface); 364 view_subsurface_create(view, subsurface);
365} 365}
366 366
367static void surface_send_enter_iterator(struct wlr_surface *surface,
368 int x, int y, void *data) {
369 struct wlr_output *wlr_output = data;
370 wlr_surface_send_enter(surface, wlr_output);
371}
372
373static void surface_send_leave_iterator(struct wlr_surface *surface,
374 int x, int y, void *data) {
375 struct wlr_output *wlr_output = data;
376 wlr_surface_send_leave(surface, wlr_output);
377}
378
379static void view_handle_container_reparent(struct wl_listener *listener,
380 void *data) {
381 struct sway_view *view =
382 wl_container_of(listener, view, container_reparent);
383 struct sway_container *old_parent = data;
384
385 struct sway_container *old_output = old_parent;
386 if (old_output != NULL && old_output->type != C_OUTPUT) {
387 old_output = container_parent(old_output, C_OUTPUT);
388 }
389
390 struct sway_container *new_output = view->swayc->parent;
391 if (new_output != NULL && new_output->type != C_OUTPUT) {
392 new_output = container_parent(new_output, C_OUTPUT);
393 }
394
395 if (old_output == new_output) {
396 return;
397 }
398
399 if (old_output != NULL) {
400 view_for_each_surface(view, surface_send_leave_iterator,
401 old_output->sway_output->wlr_output);
402 }
403 if (new_output != NULL) {
404 view_for_each_surface(view, surface_send_enter_iterator,
405 new_output->sway_output->wlr_output);
406 }
407}
408
409static bool view_has_executed_criteria(struct sway_view *view, 367static bool view_has_executed_criteria(struct sway_view *view,
410 struct criteria *criteria) { 368 struct criteria *criteria) {
411 for (int i = 0; i < view->executed_criteria->length; ++i) { 369 for (int i = 0; i < view->executed_criteria->length; ++i) {
@@ -567,9 +525,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
567 &view->surface_new_subsurface); 525 &view->surface_new_subsurface);
568 view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; 526 view->surface_new_subsurface.notify = view_handle_surface_new_subsurface;
569 527
570 wl_signal_add(&view->swayc->events.reparent, &view->container_reparent);
571 view->container_reparent.notify = view_handle_container_reparent;
572
573 if (view->impl->wants_floating && view->impl->wants_floating(view)) { 528 if (view->impl->wants_floating && view->impl->wants_floating(view)) {
574 view->border = config->floating_border; 529 view->border = config->floating_border;
575 view->border_thickness = config->floating_border_thickness; 530 view->border_thickness = config->floating_border_thickness;
@@ -587,15 +542,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
587 view_update_title(view, false); 542 view_update_title(view, false);
588 container_notify_subtree_changed(view->swayc->parent); 543 container_notify_subtree_changed(view->swayc->parent);
589 view_execute_criteria(view); 544 view_execute_criteria(view);
590
591 view_handle_container_reparent(&view->container_reparent, NULL);
592} 545}
593 546
594void view_unmap(struct sway_view *view) { 547void view_unmap(struct sway_view *view) {
595 wl_signal_emit(&view->events.unmap, view); 548 wl_signal_emit(&view->events.unmap, view);
596 549
597 wl_list_remove(&view->surface_new_subsurface.link); 550 wl_list_remove(&view->surface_new_subsurface.link);
598 wl_list_remove(&view->container_reparent.link);
599 551
600 if (view->urgent_timer) { 552 if (view->urgent_timer) {
601 wl_event_source_remove(view->urgent_timer); 553 wl_event_source_remove(view->urgent_timer);
@@ -937,10 +889,8 @@ void view_add_mark(struct sway_view *view, char *mark) {
937 889
938static void update_marks_texture(struct sway_view *view, 890static void update_marks_texture(struct sway_view *view,
939 struct wlr_texture **texture, struct border_colors *class) { 891 struct wlr_texture **texture, struct border_colors *class) {
940 struct sway_container *output = container_parent(view->swayc, C_OUTPUT); 892 struct sway_output *output =
941 if (!output) { 893 view->swayc->outputs->items[view->swayc->outputs->length - 1];
942 return;
943 }
944 if (*texture) { 894 if (*texture) {
945 wlr_texture_destroy(*texture); 895 wlr_texture_destroy(*texture);
946 *texture = NULL; 896 *texture = NULL;
@@ -973,7 +923,7 @@ static void update_marks_texture(struct sway_view *view,
973 } 923 }
974 free(part); 924 free(part);
975 925
976 double scale = output->sway_output->wlr_output->scale; 926 double scale = output->wlr_output->scale;
977 int width = 0; 927 int width = 0;
978 int height = view->swayc->title_height * scale; 928 int height = view->swayc->title_height * scale;
979 929
@@ -999,7 +949,7 @@ static void update_marks_texture(struct sway_view *view,
999 unsigned char *data = cairo_image_surface_get_data(surface); 949 unsigned char *data = cairo_image_surface_get_data(surface);
1000 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); 950 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
1001 struct wlr_renderer *renderer = wlr_backend_get_renderer( 951 struct wlr_renderer *renderer = wlr_backend_get_renderer(
1002 output->sway_output->wlr_output->backend); 952 output->wlr_output->backend);
1003 *texture = wlr_texture_from_pixels( 953 *texture = wlr_texture_from_pixels(
1004 renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); 954 renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data);
1005 cairo_surface_destroy(surface); 955 cairo_surface_destroy(surface);