aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop')
-rw-r--r--sway/desktop/output.c70
-rw-r--r--sway/desktop/transaction.c214
-rw-r--r--sway/desktop/xdg_shell.c29
-rw-r--r--sway/desktop/xdg_shell_v6.c30
-rw-r--r--sway/desktop/xwayland.c33
5 files changed, 317 insertions, 59 deletions
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 3142bdb4..c5d445a6 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -69,6 +69,7 @@ struct render_data {
69 struct root_geometry root_geo; 69 struct root_geometry root_geo;
70 struct sway_output *output; 70 struct sway_output *output;
71 pixman_region32_t *damage; 71 pixman_region32_t *damage;
72 struct sway_view *view;
72 float alpha; 73 float alpha;
73}; 74};
74 75
@@ -108,6 +109,38 @@ static bool get_surface_box(struct root_geometry *geo,
108 return wlr_box_intersection(&output_box, &rotated_box, &intersection); 109 return wlr_box_intersection(&output_box, &rotated_box, &intersection);
109} 110}
110 111
112static bool get_view_box(struct root_geometry *geo,
113 struct sway_output *output, struct sway_view *view, int sx, int sy,
114 struct wlr_box *surface_box) {
115 int sw = view->width;
116 int sh = view->height;
117
118 double _sx = sx, _sy = sy;
119 rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height,
120 geo->rotation);
121
122 struct wlr_box box = {
123 .x = geo->x + _sx,
124 .y = geo->y + _sy,
125 .width = sw,
126 .height = sh,
127 };
128 if (surface_box != NULL) {
129 memcpy(surface_box, &box, sizeof(struct wlr_box));
130 }
131
132 struct wlr_box rotated_box;
133 wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box);
134
135 struct wlr_box output_box = {
136 .width = output->swayc->width,
137 .height = output->swayc->height,
138 };
139
140 struct wlr_box intersection;
141 return wlr_box_intersection(&output_box, &rotated_box, &intersection);
142}
143
111static void surface_for_each_surface(struct wlr_surface *surface, 144static void surface_for_each_surface(struct wlr_surface *surface,
112 double ox, double oy, struct root_geometry *geo, 145 double ox, double oy, struct root_geometry *geo,
113 wlr_surface_iterator_func_t iterator, void *user_data) { 146 wlr_surface_iterator_func_t iterator, void *user_data) {
@@ -225,13 +258,26 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
225 pixman_region32_t *output_damage = data->damage; 258 pixman_region32_t *output_damage = data->damage;
226 float alpha = data->alpha; 259 float alpha = data->alpha;
227 260
228 if (!wlr_surface_has_buffer(surface)) { 261 struct wlr_texture *texture = NULL;
229 return; 262 struct wlr_box box;
263 bool intersects;
264
265 // If this is the main surface of a view, render the saved_texture instead
266 // if it exists. It exists when we are mid-transaction.
267 if (data->view && data->view->saved_texture &&
268 data->view->surface == surface) {
269 texture = data->view->saved_texture;
270 intersects = get_view_box(&data->root_geo, data->output, data->view,
271 sx, sy, &box);
272 } else {
273 if (!wlr_surface_has_buffer(surface)) {
274 return;
275 }
276 texture = surface->texture;
277 intersects = get_surface_box(&data->root_geo, data->output, surface,
278 sx, sy, &box);
230 } 279 }
231 280
232 struct wlr_box box;
233 bool intersects = get_surface_box(&data->root_geo, data->output, surface,
234 sx, sy, &box);
235 if (!intersects) { 281 if (!intersects) {
236 return; 282 return;
237 } 283 }
@@ -244,8 +290,7 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
244 wlr_matrix_project_box(matrix, &box, transform, rotation, 290 wlr_matrix_project_box(matrix, &box, transform, rotation,
245 wlr_output->transform_matrix); 291 wlr_output->transform_matrix);
246 292
247 render_texture(wlr_output, output_damage, surface->texture, &box, matrix, 293 render_texture(wlr_output, output_damage, texture, &box, matrix, alpha);
248 alpha);
249} 294}
250 295
251static void render_layer(struct sway_output *output, 296static void render_layer(struct sway_output *output,
@@ -315,6 +360,7 @@ static void render_view_surfaces(struct sway_view *view,
315 struct render_data data = { 360 struct render_data data = {
316 .output = output, 361 .output = output,
317 .damage = damage, 362 .damage = damage,
363 .view = view,
318 .alpha = alpha, 364 .alpha = alpha,
319 }; 365 };
320 output_view_for_each_surface( 366 output_view_for_each_surface(
@@ -1134,6 +1180,16 @@ void output_damage_from_view(struct sway_output *output,
1134 output_damage_view(output, view, false); 1180 output_damage_view(output, view, false);
1135} 1181}
1136 1182
1183// Expecting an unscaled box in layout coordinates
1184void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
1185 struct wlr_box box;
1186 memcpy(&box, _box, sizeof(struct wlr_box));
1187 box.x -= output->swayc->x;
1188 box.y -= output->swayc->y;
1189 scale_box(&box, output->wlr_output->scale);
1190 wlr_output_damage_add_box(output->damage, &box);
1191}
1192
1137static void output_damage_whole_container_iterator(struct sway_container *con, 1193static void output_damage_whole_container_iterator(struct sway_container *con,
1138 void *data) { 1194 void *data) {
1139 struct sway_output *output = data; 1195 struct sway_output *output = data;
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
new file mode 100644
index 00000000..69f97e3d
--- /dev/null
+++ b/sway/desktop/transaction.c
@@ -0,0 +1,214 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdbool.h>
3#include <stdlib.h>
4#include <string.h>
5#include <wlr/types/wlr_linux_dmabuf.h>
6#include "sway/debug.h"
7#include "sway/desktop/transaction.h"
8#include "sway/output.h"
9#include "sway/tree/container.h"
10#include "sway/tree/view.h"
11#include "list.h"
12#include "log.h"
13
14/**
15 * How long we should wait for views to respond to the configure before giving
16 * up and applying the transaction anyway.
17 */
18#define TIMEOUT_MS 200
19
20struct sway_transaction_instruction {
21 struct sway_transaction *transaction;
22 struct sway_container *container;
23 struct sway_container_state state;
24 uint32_t serial;
25};
26
27struct sway_transaction *transaction_create() {
28 struct sway_transaction *transaction =
29 calloc(1, sizeof(struct sway_transaction));
30 transaction->instructions = create_list();
31 transaction->damage = create_list();
32 return transaction;
33}
34
35static void transaction_destroy(struct sway_transaction *transaction) {
36 int i;
37 // Free instructions
38 for (i = 0; i < transaction->instructions->length; ++i) {
39 struct sway_transaction_instruction *instruction =
40 transaction->instructions->items[i];
41 if (instruction->container->type == C_VIEW) {
42 struct sway_view *view = instruction->container->sway_view;
43 for (int j = 0; j < view->instructions->length; ++j) {
44 if (view->instructions->items[j] == instruction) {
45 list_del(view->instructions, j);
46 break;
47 }
48 }
49 }
50 free(instruction);
51 }
52 list_free(transaction->instructions);
53
54 // Free damage
55 for (i = 0; i < transaction->damage->length; ++i) {
56 struct wlr_box *box = transaction->damage->items[i];
57 free(box);
58 }
59 list_free(transaction->damage);
60
61 free(transaction);
62}
63
64void transaction_add_container(struct sway_transaction *transaction,
65 struct sway_container *container) {
66 struct sway_transaction_instruction *instruction =
67 calloc(1, sizeof(struct sway_transaction_instruction));
68 instruction->transaction = transaction;
69 instruction->container = container;
70 memcpy(&instruction->state, &container->pending,
71 sizeof(struct sway_container_state));
72 list_add(transaction->instructions, instruction);
73}
74
75void transaction_add_damage(struct sway_transaction *transaction,
76 struct wlr_box *_box) {
77 struct wlr_box *box = calloc(1, sizeof(struct wlr_box));
78 memcpy(box, _box, sizeof(struct wlr_box));
79 list_add(transaction->damage, box);
80}
81
82static void save_view_texture(struct sway_view *view) {
83 wlr_texture_destroy(view->saved_texture);
84 view->saved_texture = NULL;
85
86 // TODO: Copy the texture and store it in view->saved_texture.
87}
88
89static void remove_saved_view_texture(struct sway_view *view) {
90 wlr_texture_destroy(view->saved_texture);
91 view->saved_texture = NULL;
92}
93
94/**
95 * Apply a transaction to the "current" state of the tree.
96 *
97 * This is mostly copying stuff from the pending state into the main swayc
98 * properties, but also includes reparenting and deleting containers.
99 */
100static void transaction_apply(struct sway_transaction *transaction) {
101 int i;
102 for (i = 0; i < transaction->instructions->length; ++i) {
103 struct sway_transaction_instruction *instruction =
104 transaction->instructions->items[i];
105 struct sway_container_state *state = &instruction->state;
106 struct sway_container *container = instruction->container;
107
108 container->layout = state->layout;
109 container->x = state->swayc_x;
110 container->y = state->swayc_y;
111 container->width = state->swayc_width;
112 container->height = state->swayc_height;
113
114 if (container->type == C_VIEW) {
115 struct sway_view *view = container->sway_view;
116 view->x = state->view_x;
117 view->y = state->view_y;
118 view->width = state->view_width;
119 view->height = state->view_height;
120 view->is_fullscreen = state->is_fullscreen;
121 view->border = state->border;
122 view->border_thickness = state->border_thickness;
123 view->border_top = state->border_top;
124 view->border_left = state->border_left;
125 view->border_right = state->border_right;
126 view->border_bottom = state->border_bottom;
127
128 remove_saved_view_texture(view);
129 }
130 }
131
132 // Damage
133 for (i = 0; i < transaction->damage->length; ++i) {
134 struct wlr_box *box = transaction->damage->items[i];
135 for (int j = 0; j < root_container.children->length; ++j) {
136 struct sway_container *output = root_container.children->items[j];
137 output_damage_box(output->sway_output, box);
138 }
139 }
140
141 update_debug_tree();
142}
143
144static int handle_timeout(void *data) {
145 struct sway_transaction *transaction = data;
146 wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting), applying anyway",
147 transaction, transaction->num_waiting);
148 transaction_apply(transaction);
149 transaction_destroy(transaction);
150 return 0;
151}
152
153void transaction_commit(struct sway_transaction *transaction) {
154 wlr_log(L_DEBUG, "Transaction %p committing with %i instructions",
155 transaction, transaction->instructions->length);
156 transaction->num_waiting = 0;
157 for (int i = 0; i < transaction->instructions->length; ++i) {
158 struct sway_transaction_instruction *instruction =
159 transaction->instructions->items[i];
160 if (instruction->container->type == C_VIEW) {
161 struct sway_view *view = instruction->container->sway_view;
162 instruction->serial = view_configure(view,
163 instruction->state.view_x,
164 instruction->state.view_y,
165 instruction->state.view_width,
166 instruction->state.view_height);
167 if (instruction->serial) {
168 save_view_texture(view);
169 list_add(view->instructions, instruction);
170 ++transaction->num_waiting;
171 }
172 }
173 }
174 if (!transaction->num_waiting) {
175 // This can happen if the transaction only contains xwayland views
176 wlr_log(L_DEBUG, "Transaction %p has nothing to wait for, applying",
177 transaction);
178 transaction_apply(transaction);
179 transaction_destroy(transaction);
180 return;
181 }
182
183 // Set up a timer which the views must respond within
184 transaction->timer = wl_event_loop_add_timer(server.wl_event_loop,
185 handle_timeout, transaction);
186 wl_event_source_timer_update(transaction->timer, TIMEOUT_MS);
187}
188
189void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) {
190 // Find the instruction
191 struct sway_transaction_instruction *instruction = NULL;
192 for (int i = 0; i < view->instructions->length; ++i) {
193 struct sway_transaction_instruction *tmp_instruction =
194 view->instructions->items[i];
195 if (tmp_instruction->serial == serial) {
196 instruction = tmp_instruction;
197 list_del(view->instructions, i);
198 break;
199 }
200 }
201 if (!instruction) {
202 // This can happen if the view acknowledges the configure after the
203 // transaction has timed out and applied.
204 return;
205 }
206 // If all views are ready, apply the transaction
207 struct sway_transaction *transaction = instruction->transaction;
208 if (--transaction->num_waiting == 0) {
209 wlr_log(L_DEBUG, "Transaction %p is ready, applying", transaction);
210 wl_event_source_timer_update(transaction->timer, 0);
211 transaction_apply(transaction);
212 transaction_destroy(transaction);
213 }
214}
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index d2b8822c..f43a0a1b 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -5,6 +5,7 @@
5#include <wlr/types/wlr_xdg_shell.h> 5#include <wlr/types/wlr_xdg_shell.h>
6#include <wlr/util/edges.h> 6#include <wlr/util/edges.h>
7#include "log.h" 7#include "log.h"
8#include "sway/desktop/transaction.h"
8#include "sway/input/input-manager.h" 9#include "sway/input/input-manager.h"
9#include "sway/input/seat.h" 10#include "sway/input/seat.h"
10#include "sway/server.h" 11#include "sway/server.h"
@@ -87,18 +88,14 @@ static const char *get_string_prop(struct sway_view *view, enum sway_view_prop p
87 } 88 }
88} 89}
89 90
90static void configure(struct sway_view *view, double lx, double ly, int width, 91static uint32_t configure(struct sway_view *view, double lx, double ly,
91 int height) { 92 int width, int height) {
92 struct sway_xdg_shell_view *xdg_shell_view = 93 struct sway_xdg_shell_view *xdg_shell_view =
93 xdg_shell_view_from_view(view); 94 xdg_shell_view_from_view(view);
94 if (xdg_shell_view == NULL) { 95 if (xdg_shell_view == NULL) {
95 return; 96 return 0;
96 } 97 }
97 98 return wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
98 xdg_shell_view->pending_width = width;
99 xdg_shell_view->pending_height = height;
100 wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
101 view_update_position(view, lx, ly);
102} 99}
103 100
104static void set_activated(struct sway_view *view, bool activated) { 101static void set_activated(struct sway_view *view, bool activated) {
@@ -174,18 +171,12 @@ static void handle_commit(struct wl_listener *listener, void *data) {
174 struct sway_xdg_shell_view *xdg_shell_view = 171 struct sway_xdg_shell_view *xdg_shell_view =
175 wl_container_of(listener, xdg_shell_view, commit); 172 wl_container_of(listener, xdg_shell_view, commit);
176 struct sway_view *view = &xdg_shell_view->view; 173 struct sway_view *view = &xdg_shell_view->view;
177 if (view->swayc && container_is_floating(view->swayc)) { 174 struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
178 int width = view->wlr_xdg_surface->geometry.width; 175
179 int height = view->wlr_xdg_surface->geometry.height; 176 if (view->instructions->length) {
180 if (!width && !height) { 177 transaction_notify_view_ready(view, xdg_surface->configure_serial);
181 width = view->wlr_xdg_surface->surface->current->width;
182 height = view->wlr_xdg_surface->surface->current->height;
183 }
184 view_update_size(view, width, height);
185 } else {
186 view_update_size(view, xdg_shell_view->pending_width,
187 xdg_shell_view->pending_height);
188 } 178 }
179
189 view_update_title(view, false); 180 view_update_title(view, false);
190 view_damage_from(view); 181 view_damage_from(view);
191} 182}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 6ffe334a..bce59174 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -3,6 +3,7 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <wayland-server.h> 4#include <wayland-server.h>
5#include <wlr/types/wlr_xdg_shell_v6.h> 5#include <wlr/types/wlr_xdg_shell_v6.h>
6#include "sway/desktop/transaction.h"
6#include "sway/tree/container.h" 7#include "sway/tree/container.h"
7#include "sway/tree/layout.h" 8#include "sway/tree/layout.h"
8#include "sway/server.h" 9#include "sway/server.h"
@@ -86,18 +87,15 @@ static const char *get_string_prop(struct sway_view *view, enum sway_view_prop p
86 } 87 }
87} 88}
88 89
89static void configure(struct sway_view *view, double lx, double ly, int width, 90static uint32_t configure(struct sway_view *view, double lx, double ly,
90 int height) { 91 int width, int height) {
91 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 92 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
92 xdg_shell_v6_view_from_view(view); 93 xdg_shell_v6_view_from_view(view);
93 if (xdg_shell_v6_view == NULL) { 94 if (xdg_shell_v6_view == NULL) {
94 return; 95 return 0;
95 } 96 }
96 97 return wlr_xdg_toplevel_v6_set_size(
97 xdg_shell_v6_view->pending_width = width; 98 view->wlr_xdg_surface_v6, width, height);
98 xdg_shell_v6_view->pending_height = height;
99 wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height);
100 view_update_position(view, lx, ly);
101} 99}
102 100
103static void set_activated(struct sway_view *view, bool activated) { 101static void set_activated(struct sway_view *view, bool activated) {
@@ -173,18 +171,12 @@ static void handle_commit(struct wl_listener *listener, void *data) {
173 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 171 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
174 wl_container_of(listener, xdg_shell_v6_view, commit); 172 wl_container_of(listener, xdg_shell_v6_view, commit);
175 struct sway_view *view = &xdg_shell_v6_view->view; 173 struct sway_view *view = &xdg_shell_v6_view->view;
176 if (view->swayc && container_is_floating(view->swayc)) { 174 struct wlr_xdg_surface_v6 *xdg_surface_v6 = view->wlr_xdg_surface_v6;
177 int width = view->wlr_xdg_surface_v6->geometry.width; 175
178 int height = view->wlr_xdg_surface_v6->geometry.height; 176 if (view->instructions->length) {
179 if (!width && !height) { 177 transaction_notify_view_ready(view, xdg_surface_v6->configure_serial);
180 width = view->wlr_xdg_surface_v6->surface->current->width;
181 height = view->wlr_xdg_surface_v6->surface->current->height;
182 }
183 view_update_size(view, width, height);
184 } else {
185 view_update_size(view, xdg_shell_v6_view->pending_width,
186 xdg_shell_v6_view->pending_height);
187 } 178 }
179
188 view_update_title(view, false); 180 view_update_title(view, false);
189 view_damage_from(view); 181 view_damage_from(view);
190} 182}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 6447b711..6a3c1b66 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -167,19 +167,18 @@ static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) {
167 } 167 }
168} 168}
169 169
170static void configure(struct sway_view *view, double lx, double ly, int width, 170static uint32_t configure(struct sway_view *view, double lx, double ly, int width,
171 int height) { 171 int height) {
172 struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); 172 struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
173 if (xwayland_view == NULL) { 173 if (xwayland_view == NULL) {
174 return; 174 return 0;
175 } 175 }
176 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; 176 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
177 177
178 xwayland_view->pending_lx = lx;
179 xwayland_view->pending_ly = ly;
180 xwayland_view->pending_width = width;
181 xwayland_view->pending_height = height;
182 wlr_xwayland_surface_configure(xsurface, lx, ly, width, height); 178 wlr_xwayland_surface_configure(xsurface, lx, ly, width, height);
179
180 // xwayland doesn't give us a serial for the configure
181 return 0;
183} 182}
184 183
185static void set_activated(struct sway_view *view, bool activated) { 184static void set_activated(struct sway_view *view, bool activated) {
@@ -250,15 +249,21 @@ static void handle_commit(struct wl_listener *listener, void *data) {
250 wl_container_of(listener, xwayland_view, commit); 249 wl_container_of(listener, xwayland_view, commit);
251 struct sway_view *view = &xwayland_view->view; 250 struct sway_view *view = &xwayland_view->view;
252 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; 251 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
253 if (view->swayc && container_is_floating(view->swayc)) { 252
254 view_update_size(view, xsurface->width, xsurface->height); 253 // Don't allow xwayland views to do resize or reposition themselves if
255 } else { 254 // they're involved in a transaction. Once the transaction has finished
256 view_update_size(view, xwayland_view->pending_width, 255 // they'll apply the next time a commit happens.
257 xwayland_view->pending_height); 256 if (view->instructions->length) {
257 if (view->swayc && container_is_floating(view->swayc)) {
258 view_update_size(view, xsurface->width, xsurface->height);
259 } else {
260 view_update_size(view, view->swayc->pending.swayc_width,
261 view->swayc->pending.swayc_height);
262 }
263 view_update_position(view,
264 view->swayc->pending.view_x, view->swayc->pending.view_y);
265 view_damage_from(view);
258 } 266 }
259 view_update_position(view,
260 xwayland_view->pending_lx, xwayland_view->pending_ly);
261 view_damage_from(view);
262} 267}
263 268
264static void handle_unmap(struct wl_listener *listener, void *data) { 269static void handle_unmap(struct wl_listener *listener, void *data) {