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