aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/xdg_shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop/xdg_shell.c')
-rw-r--r--sway/desktop/xdg_shell.c384
1 files changed, 204 insertions, 180 deletions
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 667fb9e5..7cdd97c8 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -7,7 +7,7 @@
7#include <wlr/util/edges.h> 7#include <wlr/util/edges.h>
8#include "log.h" 8#include "log.h"
9#include "sway/decoration.h" 9#include "sway/decoration.h"
10#include "sway/desktop.h" 10#include "sway/scene_descriptor.h"
11#include "sway/desktop/transaction.h" 11#include "sway/desktop/transaction.h"
12#include "sway/input/cursor.h" 12#include "sway/input/cursor.h"
13#include "sway/input/input-manager.h" 13#include "sway/input/input-manager.h"
@@ -19,64 +19,44 @@
19#include "sway/tree/workspace.h" 19#include "sway/tree/workspace.h"
20#include "sway/xdg_decoration.h" 20#include "sway/xdg_decoration.h"
21 21
22static const struct sway_view_child_impl popup_impl;
23
24static void popup_get_root_coords(struct sway_view_child *child,
25 int *root_sx, int *root_sy) {
26 struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
27 struct wlr_xdg_surface *surface = popup->wlr_xdg_surface;
28
29 int x_offset = -child->view->geometry.x - surface->geometry.x;
30 int y_offset = -child->view->geometry.y - surface->geometry.y;
31
32 wlr_xdg_popup_get_toplevel_coords(surface->popup,
33 x_offset + surface->popup->geometry.x,
34 y_offset + surface->popup->geometry.y,
35 root_sx, root_sy);
36}
37
38static void popup_destroy(struct sway_view_child *child) {
39 if (!sway_assert(child->impl == &popup_impl,
40 "Expected an xdg_shell popup")) {
41 return;
42 }
43 struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
44 wl_list_remove(&popup->new_popup.link);
45 wl_list_remove(&popup->destroy.link);
46 free(popup);
47}
48
49static const struct sway_view_child_impl popup_impl = {
50 .get_root_coords = popup_get_root_coords,
51 .destroy = popup_destroy,
52};
53
54static struct sway_xdg_popup *popup_create( 22static struct sway_xdg_popup *popup_create(
55 struct wlr_xdg_popup *wlr_popup, struct sway_view *view); 23 struct wlr_xdg_popup *wlr_popup, struct sway_view *view,
24 struct wlr_scene_tree *parent);
56 25
57static void popup_handle_new_popup(struct wl_listener *listener, void *data) { 26static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
58 struct sway_xdg_popup *popup = 27 struct sway_xdg_popup *popup =
59 wl_container_of(listener, popup, new_popup); 28 wl_container_of(listener, popup, new_popup);
60 struct wlr_xdg_popup *wlr_popup = data; 29 struct wlr_xdg_popup *wlr_popup = data;
61 popup_create(wlr_popup, popup->child.view); 30 popup_create(wlr_popup, popup->view, popup->xdg_surface_tree);
62} 31}
63 32
64static void popup_handle_destroy(struct wl_listener *listener, void *data) { 33static void popup_handle_destroy(struct wl_listener *listener, void *data) {
65 struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); 34 struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy);
66 view_child_destroy(&popup->child); 35
36 wl_list_remove(&popup->new_popup.link);
37 wl_list_remove(&popup->destroy.link);
38 wl_list_remove(&popup->surface_commit.link);
39 wlr_scene_node_destroy(&popup->scene_tree->node);
40 free(popup);
67} 41}
68 42
69static void popup_unconstrain(struct sway_xdg_popup *popup) { 43static void popup_unconstrain(struct sway_xdg_popup *popup) {
70 struct sway_view *view = popup->child.view; 44 struct sway_view *view = popup->view;
71 struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; 45 struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
72 46
73 struct sway_output *output = view->container->workspace->output; 47 struct sway_workspace *workspace = view->container->pending.workspace;
48 if (!workspace) {
49 // is null if in the scratchpad
50 return;
51 }
52
53 struct sway_output *output = workspace->output;
74 54
75 // the output box expressed in the coordinate system of the toplevel parent 55 // the output box expressed in the coordinate system of the toplevel parent
76 // of the popup 56 // of the popup
77 struct wlr_box output_toplevel_sx_box = { 57 struct wlr_box output_toplevel_sx_box = {
78 .x = output->lx - view->container->content_x, 58 .x = output->lx - view->container->pending.content_x + view->geometry.x,
79 .y = output->ly - view->container->content_y, 59 .y = output->ly - view->container->pending.content_y + view->geometry.y,
80 .width = output->width, 60 .width = output->width,
81 .height = output->height, 61 .height = output->height,
82 }; 62 };
@@ -84,32 +64,62 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) {
84 wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); 64 wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
85} 65}
86 66
87static struct sway_xdg_popup *popup_create( 67static void popup_handle_surface_commit(struct wl_listener *listener, void *data) {
88 struct wlr_xdg_popup *wlr_popup, struct sway_view *view) { 68 struct sway_xdg_popup *popup = wl_container_of(listener, popup, surface_commit);
69 if (popup->wlr_xdg_popup->base->initial_commit) {
70 popup_unconstrain(popup);
71 }
72}
73
74static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup,
75 struct sway_view *view, struct wlr_scene_tree *parent) {
89 struct wlr_xdg_surface *xdg_surface = wlr_popup->base; 76 struct wlr_xdg_surface *xdg_surface = wlr_popup->base;
90 77
91 struct sway_xdg_popup *popup = 78 struct sway_xdg_popup *popup = calloc(1, sizeof(struct sway_xdg_popup));
92 calloc(1, sizeof(struct sway_xdg_popup)); 79 if (!popup) {
93 if (popup == NULL) {
94 return NULL; 80 return NULL;
95 } 81 }
96 view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
97 popup->wlr_xdg_surface = xdg_surface;
98 82
83 popup->wlr_xdg_popup = wlr_popup;
84 popup->view = view;
85
86 popup->scene_tree = wlr_scene_tree_create(parent);
87 if (!popup->scene_tree) {
88 free(popup);
89 return NULL;
90 }
91
92 popup->xdg_surface_tree = wlr_scene_xdg_surface_create(
93 popup->scene_tree, xdg_surface);
94 if (!popup->xdg_surface_tree) {
95 wlr_scene_node_destroy(&popup->scene_tree->node);
96 free(popup);
97 return NULL;
98 }
99
100 if (!scene_descriptor_assign(&popup->scene_tree->node,
101 SWAY_SCENE_DESC_POPUP, popup)) {
102 sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor");
103 wlr_scene_node_destroy(&popup->scene_tree->node);
104 free(popup);
105 return NULL;
106 }
107
108 popup->wlr_xdg_popup = xdg_surface->popup;
109 struct sway_xdg_shell_view *shell_view =
110 wl_container_of(view, shell_view, view);
111 xdg_surface->data = shell_view;
112
113 wl_signal_add(&xdg_surface->surface->events.commit, &popup->surface_commit);
114 popup->surface_commit.notify = popup_handle_surface_commit;
99 wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); 115 wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
100 popup->new_popup.notify = popup_handle_new_popup; 116 popup->new_popup.notify = popup_handle_new_popup;
101 wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); 117 wl_signal_add(&wlr_popup->events.destroy, &popup->destroy);
102 popup->destroy.notify = popup_handle_destroy; 118 popup->destroy.notify = popup_handle_destroy;
103 119
104 wl_signal_add(&xdg_surface->events.map, &popup->child.surface_map);
105 wl_signal_add(&xdg_surface->events.unmap, &popup->child.surface_unmap);
106
107 popup_unconstrain(popup);
108
109 return popup; 120 return popup;
110} 121}
111 122
112
113static struct sway_xdg_shell_view *xdg_shell_view_from_view( 123static struct sway_xdg_shell_view *xdg_shell_view_from_view(
114 struct sway_view *view) { 124 struct sway_view *view) {
115 if (!sway_assert(view->type == SWAY_VIEW_XDG_SHELL, 125 if (!sway_assert(view->type == SWAY_VIEW_XDG_SHELL,
@@ -122,7 +132,7 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view(
122static void get_constraints(struct sway_view *view, double *min_width, 132static void get_constraints(struct sway_view *view, double *min_width,
123 double *max_width, double *min_height, double *max_height) { 133 double *max_width, double *min_height, double *max_height) {
124 struct wlr_xdg_toplevel_state *state = 134 struct wlr_xdg_toplevel_state *state =
125 &view->wlr_xdg_surface->toplevel->current; 135 &view->wlr_xdg_toplevel->current;
126 *min_width = state->min_width > 0 ? state->min_width : DBL_MIN; 136 *min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
127 *max_width = state->max_width > 0 ? state->max_width : DBL_MAX; 137 *max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
128 *min_height = state->min_height > 0 ? state->min_height : DBL_MIN; 138 *min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
@@ -136,9 +146,9 @@ static const char *get_string_prop(struct sway_view *view,
136 } 146 }
137 switch (prop) { 147 switch (prop) {
138 case VIEW_PROP_TITLE: 148 case VIEW_PROP_TITLE:
139 return view->wlr_xdg_surface->toplevel->title; 149 return view->wlr_xdg_toplevel->title;
140 case VIEW_PROP_APP_ID: 150 case VIEW_PROP_APP_ID:
141 return view->wlr_xdg_surface->toplevel->app_id; 151 return view->wlr_xdg_toplevel->app_id;
142 default: 152 default:
143 return NULL; 153 return NULL;
144 } 154 }
@@ -151,50 +161,52 @@ static uint32_t configure(struct sway_view *view, double lx, double ly,
151 if (xdg_shell_view == NULL) { 161 if (xdg_shell_view == NULL) {
152 return 0; 162 return 0;
153 } 163 }
154 return wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height); 164 return wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel,
165 width, height);
155} 166}
156 167
157static void set_activated(struct sway_view *view, bool activated) { 168static void set_activated(struct sway_view *view, bool activated) {
158 if (xdg_shell_view_from_view(view) == NULL) { 169 if (xdg_shell_view_from_view(view) == NULL) {
159 return; 170 return;
160 } 171 }
161 struct wlr_xdg_surface *surface = view->wlr_xdg_surface; 172 wlr_xdg_toplevel_set_activated(view->wlr_xdg_toplevel, activated);
162 if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
163 wlr_xdg_toplevel_set_activated(surface, activated);
164 }
165} 173}
166 174
167static void set_tiled(struct sway_view *view, bool tiled) { 175static void set_tiled(struct sway_view *view, bool tiled) {
168 if (xdg_shell_view_from_view(view) == NULL) { 176 if (xdg_shell_view_from_view(view) == NULL) {
169 return; 177 return;
170 } 178 }
171 struct wlr_xdg_surface *surface = view->wlr_xdg_surface; 179 if (wl_resource_get_version(view->wlr_xdg_toplevel->resource) >=
172 enum wlr_edges edges = WLR_EDGE_NONE; 180 XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) {
173 if (tiled) { 181 enum wlr_edges edges = WLR_EDGE_NONE;
174 edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | 182 if (tiled) {
175 WLR_EDGE_BOTTOM; 183 edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP |
184 WLR_EDGE_BOTTOM;
185 }
186 wlr_xdg_toplevel_set_tiled(view->wlr_xdg_toplevel, edges);
187 } else {
188 // The version is too low for the tiled state; configure as maximized instead
189 // to stop the client from drawing decorations outside of the toplevel geometry.
190 wlr_xdg_toplevel_set_maximized(view->wlr_xdg_toplevel, tiled);
176 } 191 }
177 wlr_xdg_toplevel_set_tiled(surface, edges);
178} 192}
179 193
180static void set_fullscreen(struct sway_view *view, bool fullscreen) { 194static void set_fullscreen(struct sway_view *view, bool fullscreen) {
181 if (xdg_shell_view_from_view(view) == NULL) { 195 if (xdg_shell_view_from_view(view) == NULL) {
182 return; 196 return;
183 } 197 }
184 struct wlr_xdg_surface *surface = view->wlr_xdg_surface; 198 wlr_xdg_toplevel_set_fullscreen(view->wlr_xdg_toplevel, fullscreen);
185 wlr_xdg_toplevel_set_fullscreen(surface, fullscreen);
186} 199}
187 200
188static void set_resizing(struct sway_view *view, bool resizing) { 201static void set_resizing(struct sway_view *view, bool resizing) {
189 if (xdg_shell_view_from_view(view) == NULL) { 202 if (xdg_shell_view_from_view(view) == NULL) {
190 return; 203 return;
191 } 204 }
192 struct wlr_xdg_surface *surface = view->wlr_xdg_surface; 205 wlr_xdg_toplevel_set_resizing(view->wlr_xdg_toplevel, resizing);
193 wlr_xdg_toplevel_set_resizing(surface, resizing);
194} 206}
195 207
196static bool wants_floating(struct sway_view *view) { 208static bool wants_floating(struct sway_view *view) {
197 struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_surface->toplevel; 209 struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
198 struct wlr_xdg_toplevel_state *state = &toplevel->current; 210 struct wlr_xdg_toplevel_state *state = &toplevel->current;
199 return (state->min_width != 0 && state->min_height != 0 211 return (state->min_width != 0 && state->min_height != 0
200 && (state->min_width == state->max_width 212 && (state->min_width == state->max_width
@@ -202,35 +214,17 @@ static bool wants_floating(struct sway_view *view) {
202 || toplevel->parent; 214 || toplevel->parent;
203} 215}
204 216
205static void for_each_surface(struct sway_view *view,
206 wlr_surface_iterator_func_t iterator, void *user_data) {
207 if (xdg_shell_view_from_view(view) == NULL) {
208 return;
209 }
210 wlr_xdg_surface_for_each_surface(view->wlr_xdg_surface, iterator,
211 user_data);
212}
213
214static void for_each_popup_surface(struct sway_view *view,
215 wlr_surface_iterator_func_t iterator, void *user_data) {
216 if (xdg_shell_view_from_view(view) == NULL) {
217 return;
218 }
219 wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_surface, iterator,
220 user_data);
221}
222
223static bool is_transient_for(struct sway_view *child, 217static bool is_transient_for(struct sway_view *child,
224 struct sway_view *ancestor) { 218 struct sway_view *ancestor) {
225 if (xdg_shell_view_from_view(child) == NULL) { 219 if (xdg_shell_view_from_view(child) == NULL) {
226 return false; 220 return false;
227 } 221 }
228 struct wlr_xdg_surface *surface = child->wlr_xdg_surface; 222 struct wlr_xdg_toplevel *toplevel = child->wlr_xdg_toplevel;
229 while (surface && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { 223 while (toplevel) {
230 if (surface->toplevel->parent == ancestor->wlr_xdg_surface) { 224 if (toplevel->parent == ancestor->wlr_xdg_toplevel) {
231 return true; 225 return true;
232 } 226 }
233 surface = surface->toplevel->parent; 227 toplevel = toplevel->parent;
234 } 228 }
235 return false; 229 return false;
236} 230}
@@ -239,17 +233,13 @@ static void _close(struct sway_view *view) {
239 if (xdg_shell_view_from_view(view) == NULL) { 233 if (xdg_shell_view_from_view(view) == NULL) {
240 return; 234 return;
241 } 235 }
242 struct wlr_xdg_surface *surface = view->wlr_xdg_surface; 236 wlr_xdg_toplevel_send_close(view->wlr_xdg_toplevel);
243 if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL
244 && surface->toplevel) {
245 wlr_xdg_toplevel_send_close(surface);
246 }
247} 237}
248 238
249static void close_popups(struct sway_view *view) { 239static void close_popups(struct sway_view *view) {
250 struct wlr_xdg_popup *popup, *tmp; 240 struct wlr_xdg_popup *popup, *tmp;
251 wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_surface->popups, link) { 241 wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_toplevel->base->popups, link) {
252 wlr_xdg_popup_destroy(popup->base); 242 wlr_xdg_popup_destroy(popup);
253 } 243 }
254} 244}
255 245
@@ -271,8 +261,6 @@ static const struct sway_view_impl view_impl = {
271 .set_fullscreen = set_fullscreen, 261 .set_fullscreen = set_fullscreen,
272 .set_resizing = set_resizing, 262 .set_resizing = set_resizing,
273 .wants_floating = wants_floating, 263 .wants_floating = wants_floating,
274 .for_each_surface = for_each_surface,
275 .for_each_popup_surface = for_each_popup_surface,
276 .is_transient_for = is_transient_for, 264 .is_transient_for = is_transient_for,
277 .close = _close, 265 .close = _close,
278 .close_popups = close_popups, 266 .close_popups = close_popups,
@@ -283,7 +271,20 @@ static void handle_commit(struct wl_listener *listener, void *data) {
283 struct sway_xdg_shell_view *xdg_shell_view = 271 struct sway_xdg_shell_view *xdg_shell_view =
284 wl_container_of(listener, xdg_shell_view, commit); 272 wl_container_of(listener, xdg_shell_view, commit);
285 struct sway_view *view = &xdg_shell_view->view; 273 struct sway_view *view = &xdg_shell_view->view;
286 struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; 274 struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base;
275
276 if (xdg_surface->initial_commit) {
277 if (view->xdg_decoration != NULL) {
278 set_xdg_decoration_mode(view->xdg_decoration);
279 }
280 // XXX: https://github.com/swaywm/sway/issues/2176
281 wlr_xdg_surface_schedule_configure(xdg_surface);
282 return;
283 }
284
285 if (!xdg_surface->surface->mapped) {
286 return;
287 }
287 288
288 struct wlr_box new_geo; 289 struct wlr_box new_geo;
289 wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); 290 wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
@@ -293,22 +294,35 @@ static void handle_commit(struct wl_listener *listener, void *data) {
293 new_geo.y != view->geometry.y; 294 new_geo.y != view->geometry.y;
294 295
295 if (new_size) { 296 if (new_size) {
296 // The view has unexpectedly sent a new size 297 // The client changed its surface size in this commit. For floating
297 desktop_damage_view(view); 298 // containers, we resize the container to match. For tiling containers,
298 view_update_size(view, new_geo.width, new_geo.height); 299 // we only recenter the surface.
299 memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); 300 memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
300 desktop_damage_view(view); 301 if (container_is_floating(view->container)) {
301 transaction_commit_dirty(); 302 view_update_size(view);
303 // Only set the toplevel size the current container actually has a size.
304 if (view->container->current.width) {
305 wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel, view->geometry.width,
306 view->geometry.height);
307 }
308 transaction_commit_dirty_client();
309 }
310
311 view_center_and_clip_surface(view);
302 } 312 }
303 313
304 if (view->container->node.instruction) { 314 if (view->container->node.instruction) {
305 transaction_notify_view_ready_by_serial(view, 315 bool successful = transaction_notify_view_ready_by_serial(view,
306 xdg_surface->configure_serial); 316 xdg_surface->current.configure_serial);
307 } else if (new_size) { 317
308 transaction_notify_view_ready_immediately(view); 318 // If we saved the view and this commit isn't what we're looking for
319 // that means the user will never actually see the buffers submitted to
320 // us here. Just send frame done events to these surfaces so they can
321 // commit another time for us.
322 if (view->saved_surface_tree && !successful) {
323 view_send_frame_done(view);
324 }
309 } 325 }
310
311 view_damage_from(view);
312} 326}
313 327
314static void handle_set_title(struct wl_listener *listener, void *data) { 328static void handle_set_title(struct wl_listener *listener, void *data) {
@@ -330,31 +344,42 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
330 struct sway_xdg_shell_view *xdg_shell_view = 344 struct sway_xdg_shell_view *xdg_shell_view =
331 wl_container_of(listener, xdg_shell_view, new_popup); 345 wl_container_of(listener, xdg_shell_view, new_popup);
332 struct wlr_xdg_popup *wlr_popup = data; 346 struct wlr_xdg_popup *wlr_popup = data;
333 popup_create(wlr_popup, &xdg_shell_view->view); 347
348 struct sway_xdg_popup *popup = popup_create(wlr_popup,
349 &xdg_shell_view->view, root->layers.popup);
350 if (!popup) {
351 return;
352 }
353
354 int lx, ly;
355 wlr_scene_node_coords(&popup->view->content_tree->node, &lx, &ly);
356 wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly);
357}
358
359static void handle_request_maximize(struct wl_listener *listener, void *data) {
360 struct sway_xdg_shell_view *xdg_shell_view =
361 wl_container_of(listener, xdg_shell_view, request_maximize);
362 struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
363 wlr_xdg_surface_schedule_configure(toplevel->base);
334} 364}
335 365
336static void handle_request_fullscreen(struct wl_listener *listener, void *data) { 366static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
337 struct sway_xdg_shell_view *xdg_shell_view = 367 struct sway_xdg_shell_view *xdg_shell_view =
338 wl_container_of(listener, xdg_shell_view, request_fullscreen); 368 wl_container_of(listener, xdg_shell_view, request_fullscreen);
339 struct wlr_xdg_toplevel_set_fullscreen_event *e = data; 369 struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
340 struct wlr_xdg_surface *xdg_surface =
341 xdg_shell_view->view.wlr_xdg_surface;
342 struct sway_view *view = &xdg_shell_view->view; 370 struct sway_view *view = &xdg_shell_view->view;
343 371
344 if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL, 372 if (!toplevel->base->surface->mapped) {
345 "xdg_shell requested fullscreen of surface with role %i",
346 xdg_surface->role)) {
347 return;
348 }
349 if (!xdg_surface->mapped) {
350 return; 373 return;
351 } 374 }
352 375
353 struct sway_container *container = view->container; 376 struct sway_container *container = view->container;
354 if (e->fullscreen && e->output && e->output->data) { 377 struct wlr_xdg_toplevel_requested *req = &toplevel->requested;
355 struct sway_output *output = e->output->data; 378 if (req->fullscreen && req->fullscreen_output && req->fullscreen_output->data) {
379 struct sway_output *output = req->fullscreen_output->data;
356 struct sway_workspace *ws = output_get_active_workspace(output); 380 struct sway_workspace *ws = output_get_active_workspace(output);
357 if (ws && !container_is_scratchpad_hidden(container)) { 381 if (ws && !container_is_scratchpad_hidden(container) &&
382 container->pending.workspace != ws) {
358 if (container_is_floating(container)) { 383 if (container_is_floating(container)) {
359 workspace_add_floating(ws, container); 384 workspace_add_floating(ws, container);
360 } else { 385 } else {
@@ -363,22 +388,18 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
363 } 388 }
364 } 389 }
365 390
366 container_set_fullscreen(container, e->fullscreen); 391 container_set_fullscreen(container, req->fullscreen);
367 392
368 arrange_root(); 393 arrange_root();
369 transaction_commit_dirty(); 394 transaction_commit_dirty();
370} 395}
371 396
372static void handle_request_maximize(struct wl_listener *listener, void *data) {
373 struct wlr_xdg_surface *surface = data;
374 wlr_xdg_surface_schedule_configure(surface);
375}
376
377static void handle_request_move(struct wl_listener *listener, void *data) { 397static void handle_request_move(struct wl_listener *listener, void *data) {
378 struct sway_xdg_shell_view *xdg_shell_view = 398 struct sway_xdg_shell_view *xdg_shell_view =
379 wl_container_of(listener, xdg_shell_view, request_move); 399 wl_container_of(listener, xdg_shell_view, request_move);
380 struct sway_view *view = &xdg_shell_view->view; 400 struct sway_view *view = &xdg_shell_view->view;
381 if (!container_is_floating(view->container)) { 401 if (!container_is_floating(view->container) ||
402 view->container->pending.fullscreen_mode) {
382 return; 403 return;
383 } 404 }
384 struct wlr_xdg_toplevel_move_event *e = data; 405 struct wlr_xdg_toplevel_move_event *e = data;
@@ -413,10 +434,9 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
413 434
414 view_unmap(view); 435 view_unmap(view);
415 436
416 wl_list_remove(&xdg_shell_view->commit.link);
417 wl_list_remove(&xdg_shell_view->new_popup.link); 437 wl_list_remove(&xdg_shell_view->new_popup.link);
418 wl_list_remove(&xdg_shell_view->request_fullscreen.link);
419 wl_list_remove(&xdg_shell_view->request_maximize.link); 438 wl_list_remove(&xdg_shell_view->request_maximize.link);
439 wl_list_remove(&xdg_shell_view->request_fullscreen.link);
420 wl_list_remove(&xdg_shell_view->request_move.link); 440 wl_list_remove(&xdg_shell_view->request_move.link);
421 wl_list_remove(&xdg_shell_view->request_resize.link); 441 wl_list_remove(&xdg_shell_view->request_resize.link);
422 wl_list_remove(&xdg_shell_view->set_title.link); 442 wl_list_remove(&xdg_shell_view->set_title.link);
@@ -427,62 +447,61 @@ static void handle_map(struct wl_listener *listener, void *data) {
427 struct sway_xdg_shell_view *xdg_shell_view = 447 struct sway_xdg_shell_view *xdg_shell_view =
428 wl_container_of(listener, xdg_shell_view, map); 448 wl_container_of(listener, xdg_shell_view, map);
429 struct sway_view *view = &xdg_shell_view->view; 449 struct sway_view *view = &xdg_shell_view->view;
430 struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; 450 struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
431 451
432 view->natural_width = view->wlr_xdg_surface->geometry.width; 452 view->natural_width = toplevel->base->current.geometry.width;
433 view->natural_height = view->wlr_xdg_surface->geometry.height; 453 view->natural_height = toplevel->base->current.geometry.height;
434 if (!view->natural_width && !view->natural_height) { 454 if (!view->natural_width && !view->natural_height) {
435 view->natural_width = view->wlr_xdg_surface->surface->current.width; 455 view->natural_width = toplevel->base->surface->current.width;
436 view->natural_height = view->wlr_xdg_surface->surface->current.height; 456 view->natural_height = toplevel->base->surface->current.height;
437 } 457 }
438 458
439 bool csd = false; 459 bool csd = false;
440 460
441 if (!view->xdg_decoration) { 461 if (view->xdg_decoration) {
462 enum wlr_xdg_toplevel_decoration_v1_mode mode =
463 view->xdg_decoration->wlr_xdg_decoration->requested_mode;
464 csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
465 } else {
442 struct sway_server_decoration *deco = 466 struct sway_server_decoration *deco =
443 decoration_from_surface(xdg_surface->surface); 467 decoration_from_surface(toplevel->base->surface);
444 csd = !deco || deco->wlr_server_decoration->mode == 468 csd = !deco || deco->wlr_server_decoration->mode ==
445 WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; 469 WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
446
447 } 470 }
448 471
449 view_map(view, view->wlr_xdg_surface->surface, 472 view_map(view, toplevel->base->surface,
450 xdg_surface->toplevel->client_pending.fullscreen, 473 toplevel->requested.fullscreen,
451 xdg_surface->toplevel->client_pending.fullscreen_output, 474 toplevel->requested.fullscreen_output,
452 csd); 475 csd);
453 476
454 transaction_commit_dirty(); 477 transaction_commit_dirty();
455 478
456 xdg_shell_view->commit.notify = handle_commit;
457 wl_signal_add(&xdg_surface->surface->events.commit,
458 &xdg_shell_view->commit);
459
460 xdg_shell_view->new_popup.notify = handle_new_popup; 479 xdg_shell_view->new_popup.notify = handle_new_popup;
461 wl_signal_add(&xdg_surface->events.new_popup, 480 wl_signal_add(&toplevel->base->events.new_popup,
462 &xdg_shell_view->new_popup); 481 &xdg_shell_view->new_popup);
463 482
464 xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
465 wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
466 &xdg_shell_view->request_fullscreen);
467
468 xdg_shell_view->request_maximize.notify = handle_request_maximize; 483 xdg_shell_view->request_maximize.notify = handle_request_maximize;
469 wl_signal_add(&xdg_surface->toplevel->events.request_maximize, 484 wl_signal_add(&toplevel->events.request_maximize,
470 &xdg_shell_view->request_maximize); 485 &xdg_shell_view->request_maximize);
471 486
487 xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
488 wl_signal_add(&toplevel->events.request_fullscreen,
489 &xdg_shell_view->request_fullscreen);
490
472 xdg_shell_view->request_move.notify = handle_request_move; 491 xdg_shell_view->request_move.notify = handle_request_move;
473 wl_signal_add(&xdg_surface->toplevel->events.request_move, 492 wl_signal_add(&toplevel->events.request_move,
474 &xdg_shell_view->request_move); 493 &xdg_shell_view->request_move);
475 494
476 xdg_shell_view->request_resize.notify = handle_request_resize; 495 xdg_shell_view->request_resize.notify = handle_request_resize;
477 wl_signal_add(&xdg_surface->toplevel->events.request_resize, 496 wl_signal_add(&toplevel->events.request_resize,
478 &xdg_shell_view->request_resize); 497 &xdg_shell_view->request_resize);
479 498
480 xdg_shell_view->set_title.notify = handle_set_title; 499 xdg_shell_view->set_title.notify = handle_set_title;
481 wl_signal_add(&xdg_surface->toplevel->events.set_title, 500 wl_signal_add(&toplevel->events.set_title,
482 &xdg_shell_view->set_title); 501 &xdg_shell_view->set_title);
483 502
484 xdg_shell_view->set_app_id.notify = handle_set_app_id; 503 xdg_shell_view->set_app_id.notify = handle_set_app_id;
485 wl_signal_add(&xdg_surface->toplevel->events.set_app_id, 504 wl_signal_add(&toplevel->events.set_app_id,
486 &xdg_shell_view->set_app_id); 505 &xdg_shell_view->set_app_id);
487} 506}
488 507
@@ -496,7 +515,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
496 wl_list_remove(&xdg_shell_view->destroy.link); 515 wl_list_remove(&xdg_shell_view->destroy.link);
497 wl_list_remove(&xdg_shell_view->map.link); 516 wl_list_remove(&xdg_shell_view->map.link);
498 wl_list_remove(&xdg_shell_view->unmap.link); 517 wl_list_remove(&xdg_shell_view->unmap.link);
499 view->wlr_xdg_surface = NULL; 518 wl_list_remove(&xdg_shell_view->commit.link);
519 view->wlr_xdg_toplevel = NULL;
500 if (view->xdg_decoration) { 520 if (view->xdg_decoration) {
501 view->xdg_decoration->view = NULL; 521 view->xdg_decoration->view = NULL;
502 } 522 }
@@ -508,17 +528,12 @@ struct sway_view *view_from_wlr_xdg_surface(
508 return xdg_surface->data; 528 return xdg_surface->data;
509} 529}
510 530
511void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { 531void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) {
512 struct wlr_xdg_surface *xdg_surface = data; 532 struct wlr_xdg_toplevel *xdg_toplevel = data;
513
514 if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
515 sway_log(SWAY_DEBUG, "New xdg_shell popup");
516 return;
517 }
518 533
519 sway_log(SWAY_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'", 534 sway_log(SWAY_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'",
520 xdg_surface->toplevel->title, xdg_surface->toplevel->app_id); 535 xdg_toplevel->title, xdg_toplevel->app_id);
521 wlr_xdg_surface_ping(xdg_surface); 536 wlr_xdg_surface_ping(xdg_toplevel->base);
522 537
523 struct sway_xdg_shell_view *xdg_shell_view = 538 struct sway_xdg_shell_view *xdg_shell_view =
524 calloc(1, sizeof(struct sway_xdg_shell_view)); 539 calloc(1, sizeof(struct sway_xdg_shell_view));
@@ -526,17 +541,26 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
526 return; 541 return;
527 } 542 }
528 543
529 view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); 544 if (!view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl)) {
530 xdg_shell_view->view.wlr_xdg_surface = xdg_surface; 545 free(xdg_shell_view);
546 return;
547 }
548 xdg_shell_view->view.wlr_xdg_toplevel = xdg_toplevel;
531 549
532 xdg_shell_view->map.notify = handle_map; 550 xdg_shell_view->map.notify = handle_map;
533 wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); 551 wl_signal_add(&xdg_toplevel->base->surface->events.map, &xdg_shell_view->map);
534 552
535 xdg_shell_view->unmap.notify = handle_unmap; 553 xdg_shell_view->unmap.notify = handle_unmap;
536 wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap); 554 wl_signal_add(&xdg_toplevel->base->surface->events.unmap, &xdg_shell_view->unmap);
555
556 xdg_shell_view->commit.notify = handle_commit;
557 wl_signal_add(&xdg_toplevel->base->surface->events.commit,
558 &xdg_shell_view->commit);
537 559
538 xdg_shell_view->destroy.notify = handle_destroy; 560 xdg_shell_view->destroy.notify = handle_destroy;
539 wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy); 561 wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy);
562
563 wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base);
540 564
541 xdg_surface->data = xdg_shell_view; 565 xdg_toplevel->base->data = xdg_shell_view;
542} 566}