1 #define _POSIX_C_SOURCE 199309L
2 #include <float.h>
3 #include <stdbool.h>
4 #include <stdlib.h>
5 #include <wayland-server-core.h>
6 #include <wlr/types/wlr_output_layout.h>
7 #include <wlr/types/wlr_output.h>
8 #include <wlr/xwayland.h>
9 #include "log.h"
10 #include "sway/desktop.h"
11 #include "sway/desktop/transaction.h"
12 #include "sway/input/cursor.h"
13 #include "sway/input/input-manager.h"
14 #include "sway/input/seat.h"
15 #include "sway/output.h"
16 #include "sway/tree/arrange.h"
17 #include "sway/tree/container.h"
18 #include "sway/tree/view.h"
19 #include "sway/tree/workspace.h"
20
21 static const char *atom_map[ATOM_LAST] = {
22 "_NET_WM_WINDOW_TYPE_NORMAL",
23 "_NET_WM_WINDOW_TYPE_DIALOG",
24 "_NET_WM_WINDOW_TYPE_UTILITY",
25 "_NET_WM_WINDOW_TYPE_TOOLBAR",
26 "_NET_WM_WINDOW_TYPE_SPLASH",
27 "_NET_WM_WINDOW_TYPE_MENU",
28 "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
29 "_NET_WM_WINDOW_TYPE_POPUP_MENU",
30 "_NET_WM_WINDOW_TYPE_TOOLTIP",
31 "_NET_WM_WINDOW_TYPE_NOTIFICATION",
32 "_NET_WM_STATE_MODAL",
33 };
34
unmanaged_handle_request_configure(struct wl_listener * listener,void * data)35 static void unmanaged_handle_request_configure(struct wl_listener *listener,
36 void *data) {
37 struct sway_xwayland_unmanaged *surface =
38 wl_container_of(listener, surface, request_configure);
39 struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
40 struct wlr_xwayland_surface_configure_event *ev = data;
41 wlr_xwayland_surface_configure(xsurface, ev->x, ev->y,
42 ev->width, ev->height);
43 }
44
unmanaged_handle_commit(struct wl_listener * listener,void * data)45 static void unmanaged_handle_commit(struct wl_listener *listener, void *data) {
46 struct sway_xwayland_unmanaged *surface =
47 wl_container_of(listener, surface, commit);
48 struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
49
50 if (xsurface->x != surface->lx || xsurface->y != surface->ly) {
51 // Surface has moved
52 desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
53 true);
54 surface->lx = xsurface->x;
55 surface->ly = xsurface->y;
56 desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
57 true);
58 } else {
59 desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y,
60 false);
61 }
62 }
63
unmanaged_handle_map(struct wl_listener * listener,void * data)64 static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
65 struct sway_xwayland_unmanaged *surface =
66 wl_container_of(listener, surface, map);
67 struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
68
69 wl_list_insert(root->xwayland_unmanaged.prev, &surface->link);
70
71 wl_signal_add(&xsurface->surface->events.commit, &surface->commit);
72 surface->commit.notify = unmanaged_handle_commit;
73
74 surface->lx = xsurface->x;
75 surface->ly = xsurface->y;
76 desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true);
77
78 if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
79 struct sway_seat *seat = input_manager_current_seat();
80 struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
81 wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
82 seat_set_focus_surface(seat, xsurface->surface, false);
83 }
84 }
85
unmanaged_handle_unmap(struct wl_listener * listener,void * data)86 static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
87 struct sway_xwayland_unmanaged *surface =
88 wl_container_of(listener, surface, unmap);
89 struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
90 desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true);
91 wl_list_remove(&surface->link);
92 wl_list_remove(&surface->commit.link);
93
94 struct sway_seat *seat = input_manager_current_seat();
95 if (seat->wlr_seat->keyboard_state.focused_surface ==
96 xsurface->surface) {
97
98 // Try to find another unmanaged surface from the same process to pass
99 // focus to. This is necessary because some applications (e.g. Jetbrains
100 // IDEs) represent their multi-level menus as unmanaged surfaces, and
101 // when closing a submenu, the main menu should get input focus.
102 struct sway_xwayland_unmanaged *current;
103 wl_list_for_each(current, &root->xwayland_unmanaged, link) {
104 struct wlr_xwayland_surface *prev_xsurface =
105 current->wlr_xwayland_surface;
106 if (prev_xsurface->pid == xsurface->pid &&
107 wlr_xwayland_or_surface_wants_focus(prev_xsurface)) {
108 seat_set_focus_surface(seat, prev_xsurface->surface, false);
109 return;
110 }
111 }
112
113 // Restore focus
114 struct sway_node *previous = seat_get_focus_inactive(seat, &root->node);
115 if (previous) {
116 // Hack to get seat to re-focus the return value of get_focus
117 seat_set_focus(seat, NULL);
118 seat_set_focus(seat, previous);
119 }
120 }
121 }
122
unmanaged_handle_destroy(struct wl_listener * listener,void * data)123 static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
124 struct sway_xwayland_unmanaged *surface =
125 wl_container_of(listener, surface, destroy);
126 wl_list_remove(&surface->map.link);
127 wl_list_remove(&surface->unmap.link);
128 wl_list_remove(&surface->destroy.link);
129 free(surface);
130 }
131
create_unmanaged(struct wlr_xwayland_surface * xsurface)132 static struct sway_xwayland_unmanaged *create_unmanaged(
133 struct wlr_xwayland_surface *xsurface) {
134 struct sway_xwayland_unmanaged *surface =
135 calloc(1, sizeof(struct sway_xwayland_unmanaged));
136 if (surface == NULL) {
137 sway_log(SWAY_ERROR, "Allocation failed");
138 return NULL;
139 }
140
141 surface->wlr_xwayland_surface = xsurface;
142
143 wl_signal_add(&xsurface->events.request_configure,
144 &surface->request_configure);
145 surface->request_configure.notify = unmanaged_handle_request_configure;
146 wl_signal_add(&xsurface->events.map, &surface->map);
147 surface->map.notify = unmanaged_handle_map;
148 wl_signal_add(&xsurface->events.unmap, &surface->unmap);
149 surface->unmap.notify = unmanaged_handle_unmap;
150 wl_signal_add(&xsurface->events.destroy, &surface->destroy);
151 surface->destroy.notify = unmanaged_handle_destroy;
152
153 return surface;
154 }
155
156
xwayland_view_from_view(struct sway_view * view)157 static struct sway_xwayland_view *xwayland_view_from_view(
158 struct sway_view *view) {
159 if (!sway_assert(view->type == SWAY_VIEW_XWAYLAND,
160 "Expected xwayland view")) {
161 return NULL;
162 }
163 return (struct sway_xwayland_view *)view;
164 }
165
get_string_prop(struct sway_view * view,enum sway_view_prop prop)166 static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
167 if (xwayland_view_from_view(view) == NULL) {
168 return NULL;
169 }
170 switch (prop) {
171 case VIEW_PROP_TITLE:
172 return view->wlr_xwayland_surface->title;
173 case VIEW_PROP_CLASS:
174 return view->wlr_xwayland_surface->class;
175 case VIEW_PROP_INSTANCE:
176 return view->wlr_xwayland_surface->instance;
177 case VIEW_PROP_WINDOW_ROLE:
178 return view->wlr_xwayland_surface->role;
179 default:
180 return NULL;
181 }
182 }
183
get_int_prop(struct sway_view * view,enum sway_view_prop prop)184 static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) {
185 if (xwayland_view_from_view(view) == NULL) {
186 return 0;
187 }
188 switch (prop) {
189 case VIEW_PROP_X11_WINDOW_ID:
190 return view->wlr_xwayland_surface->window_id;
191 case VIEW_PROP_X11_PARENT_ID:
192 if (view->wlr_xwayland_surface->parent) {
193 return view->wlr_xwayland_surface->parent->window_id;
194 }
195 return 0;
196 case VIEW_PROP_WINDOW_TYPE:
197 if (view->wlr_xwayland_surface->window_type_len == 0) {
198 return 0;
199 }
200 return view->wlr_xwayland_surface->window_type[0];
201 default:
202 return 0;
203 }
204 }
205
configure(struct sway_view * view,double lx,double ly,int width,int height)206 static uint32_t configure(struct sway_view *view, double lx, double ly, int width,
207 int height) {
208 struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
209 if (xwayland_view == NULL) {
210 return 0;
211 }
212 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
213
214 wlr_xwayland_surface_configure(xsurface, lx, ly, width, height);
215
216 // xwayland doesn't give us a serial for the configure
217 return 0;
218 }
219
set_activated(struct sway_view * view,bool activated)220 static void set_activated(struct sway_view *view, bool activated) {
221 if (xwayland_view_from_view(view) == NULL) {
222 return;
223 }
224 struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
225 wlr_xwayland_surface_activate(surface, activated);
226 }
227
set_tiled(struct sway_view * view,bool tiled)228 static void set_tiled(struct sway_view *view, bool tiled) {
229 if (xwayland_view_from_view(view) == NULL) {
230 return;
231 }
232 struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
233 wlr_xwayland_surface_set_maximized(surface, tiled);
234 }
235
set_fullscreen(struct sway_view * view,bool fullscreen)236 static void set_fullscreen(struct sway_view *view, bool fullscreen) {
237 if (xwayland_view_from_view(view) == NULL) {
238 return;
239 }
240 struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
241 wlr_xwayland_surface_set_fullscreen(surface, fullscreen);
242 }
243
wants_floating(struct sway_view * view)244 static bool wants_floating(struct sway_view *view) {
245 if (xwayland_view_from_view(view) == NULL) {
246 return false;
247 }
248 struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
249 struct sway_xwayland *xwayland = &server.xwayland;
250
251 if (surface->modal) {
252 return true;
253 }
254
255 for (size_t i = 0; i < surface->window_type_len; ++i) {
256 xcb_atom_t type = surface->window_type[i];
257 if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_DIALOG] ||
258 type == xwayland->atoms[NET_WM_WINDOW_TYPE_UTILITY] ||
259 type == xwayland->atoms[NET_WM_WINDOW_TYPE_TOOLBAR] ||
260 type == xwayland->atoms[NET_WM_WINDOW_TYPE_SPLASH]) {
261 return true;
262 }
263 }
264
265 struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints;
266 if (size_hints != NULL &&
267 size_hints->min_width > 0 && size_hints->min_height > 0 &&
268 (size_hints->max_width == size_hints->min_width ||
269 size_hints->max_height == size_hints->min_height)) {
270 return true;
271 }
272
273 return false;
274 }
275
handle_set_decorations(struct wl_listener * listener,void * data)276 static void handle_set_decorations(struct wl_listener *listener, void *data) {
277 struct sway_xwayland_view *xwayland_view =
278 wl_container_of(listener, xwayland_view, set_decorations);
279 struct sway_view *view = &xwayland_view->view;
280 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
281
282 bool csd = xsurface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL;
283 view_update_csd_from_client(view, csd);
284 }
285
is_transient_for(struct sway_view * child,struct sway_view * ancestor)286 static bool is_transient_for(struct sway_view *child,
287 struct sway_view *ancestor) {
288 if (xwayland_view_from_view(child) == NULL) {
289 return false;
290 }
291 struct wlr_xwayland_surface *surface = child->wlr_xwayland_surface;
292 while (surface) {
293 if (surface->parent == ancestor->wlr_xwayland_surface) {
294 return true;
295 }
296 surface = surface->parent;
297 }
298 return false;
299 }
300
_close(struct sway_view * view)301 static void _close(struct sway_view *view) {
302 if (xwayland_view_from_view(view) == NULL) {
303 return;
304 }
305 wlr_xwayland_surface_close(view->wlr_xwayland_surface);
306 }
307
destroy(struct sway_view * view)308 static void destroy(struct sway_view *view) {
309 struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
310 if (xwayland_view == NULL) {
311 return;
312 }
313 free(xwayland_view);
314 }
315
get_constraints(struct sway_view * view,double * min_width,double * max_width,double * min_height,double * max_height)316 static void get_constraints(struct sway_view *view, double *min_width,
317 double *max_width, double *min_height, double *max_height) {
318 struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
319 struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints;
320
321 if (size_hints == NULL) {
322 *min_width = DBL_MIN;
323 *max_width = DBL_MAX;
324 *min_height = DBL_MIN;
325 *max_height = DBL_MAX;
326 return;
327 }
328
329 *min_width = size_hints->min_width > 0 ? size_hints->min_width : DBL_MIN;
330 *max_width = size_hints->max_width > 0 ? size_hints->max_width : DBL_MAX;
331 *min_height = size_hints->min_height > 0 ? size_hints->min_height : DBL_MIN;
332 *max_height = size_hints->max_height > 0 ? size_hints->max_height : DBL_MAX;
333 }
334
335 static const struct sway_view_impl view_impl = {
336 .get_constraints = get_constraints,
337 .get_string_prop = get_string_prop,
338 .get_int_prop = get_int_prop,
339 .configure = configure,
340 .set_activated = set_activated,
341 .set_tiled = set_tiled,
342 .set_fullscreen = set_fullscreen,
343 .wants_floating = wants_floating,
344 .is_transient_for = is_transient_for,
345 .close = _close,
346 .destroy = destroy,
347 };
348
get_geometry(struct sway_view * view,struct wlr_box * box)349 static void get_geometry(struct sway_view *view, struct wlr_box *box) {
350 box->x = box->y = 0;
351 if (view->surface) {
352 box->width = view->surface->current.width;
353 box->height = view->surface->current.height;
354 } else {
355 box->width = 0;
356 box->height = 0;
357 }
358 }
359
handle_commit(struct wl_listener * listener,void * data)360 static void handle_commit(struct wl_listener *listener, void *data) {
361 struct sway_xwayland_view *xwayland_view =
362 wl_container_of(listener, xwayland_view, commit);
363 struct sway_view *view = &xwayland_view->view;
364 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
365 struct wlr_surface_state *state = &xsurface->surface->current;
366
367 if (view->container->node.instruction) {
368 get_geometry(view, &view->geometry);
369 transaction_notify_view_ready_by_size(view,
370 state->width, state->height);
371 } else {
372 struct wlr_box new_geo;
373 get_geometry(view, &new_geo);
374
375 if ((new_geo.width != view->geometry.width ||
376 new_geo.height != view->geometry.height ||
377 new_geo.x != view->geometry.x ||
378 new_geo.y != view->geometry.y)) {
379 // The view has unexpectedly sent a new size
380 // eg. The Firefox "Save As" dialog when downloading a file
381 desktop_damage_view(view);
382 view_update_size(view, new_geo.width, new_geo.height);
383 memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
384 desktop_damage_view(view);
385 transaction_commit_dirty();
386 transaction_notify_view_ready_by_size(view,
387 new_geo.width, new_geo.height);
388 } else {
389 memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
390 }
391 }
392
393 view_damage_from(view);
394 }
395
handle_destroy(struct wl_listener * listener,void * data)396 static void handle_destroy(struct wl_listener *listener, void *data) {
397 struct sway_xwayland_view *xwayland_view =
398 wl_container_of(listener, xwayland_view, destroy);
399 struct sway_view *view = &xwayland_view->view;
400
401 if (view->surface) {
402 view_unmap(view);
403 wl_list_remove(&xwayland_view->commit.link);
404 }
405
406 wl_list_remove(&xwayland_view->destroy.link);
407 wl_list_remove(&xwayland_view->request_configure.link);
408 wl_list_remove(&xwayland_view->request_fullscreen.link);
409 wl_list_remove(&xwayland_view->request_move.link);
410 wl_list_remove(&xwayland_view->request_resize.link);
411 wl_list_remove(&xwayland_view->request_activate.link);
412 wl_list_remove(&xwayland_view->set_title.link);
413 wl_list_remove(&xwayland_view->set_class.link);
414 wl_list_remove(&xwayland_view->set_role.link);
415 wl_list_remove(&xwayland_view->set_window_type.link);
416 wl_list_remove(&xwayland_view->set_hints.link);
417 wl_list_remove(&xwayland_view->set_decorations.link);
418 wl_list_remove(&xwayland_view->map.link);
419 wl_list_remove(&xwayland_view->unmap.link);
420 view_begin_destroy(&xwayland_view->view);
421 }
422
handle_unmap(struct wl_listener * listener,void * data)423 static void handle_unmap(struct wl_listener *listener, void *data) {
424 struct sway_xwayland_view *xwayland_view =
425 wl_container_of(listener, xwayland_view, unmap);
426 struct sway_view *view = &xwayland_view->view;
427
428 if (!sway_assert(view->surface, "Cannot unmap unmapped view")) {
429 return;
430 }
431
432 view_unmap(view);
433
434 wl_list_remove(&xwayland_view->commit.link);
435 }
436
handle_map(struct wl_listener * listener,void * data)437 static void handle_map(struct wl_listener *listener, void *data) {
438 struct sway_xwayland_view *xwayland_view =
439 wl_container_of(listener, xwayland_view, map);
440 struct wlr_xwayland_surface *xsurface = data;
441 struct sway_view *view = &xwayland_view->view;
442
443 if (xsurface->override_redirect) {
444 // This window used not to have the override redirect flag and has it
445 // now. Switch to unmanaged.
446 handle_destroy(&xwayland_view->destroy, view);
447 xsurface->data = NULL;
448 struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface);
449 unmanaged_handle_map(&unmanaged->map, xsurface);
450 return;
451 }
452
453 view->natural_width = xsurface->width;
454 view->natural_height = xsurface->height;
455
456 // Wire up the commit listener here, because xwayland map/unmap can change
457 // the underlying wlr_surface
458 wl_signal_add(&xsurface->surface->events.commit, &xwayland_view->commit);
459 xwayland_view->commit.notify = handle_commit;
460
461 // Put it back into the tree
462 view_map(view, xsurface->surface, xsurface->fullscreen, NULL, false);
463
464 transaction_commit_dirty();
465 }
466
handle_request_configure(struct wl_listener * listener,void * data)467 static void handle_request_configure(struct wl_listener *listener, void *data) {
468 struct sway_xwayland_view *xwayland_view =
469 wl_container_of(listener, xwayland_view, request_configure);
470 struct wlr_xwayland_surface_configure_event *ev = data;
471 struct sway_view *view = &xwayland_view->view;
472 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
473 if (!xsurface->mapped) {
474 wlr_xwayland_surface_configure(xsurface, ev->x, ev->y,
475 ev->width, ev->height);
476 return;
477 }
478 if (container_is_floating(view->container)) {
479 // Respect minimum and maximum sizes
480 view->natural_width = ev->width;
481 view->natural_height = ev->height;
482 container_floating_resize_and_center(view->container);
483
484 configure(view, view->container->content_x,
485 view->container->content_y,
486 view->container->content_width,
487 view->container->content_height);
488 node_set_dirty(&view->container->node);
489 } else {
490 configure(view, view->container->current.content_x,
491 view->container->current.content_y,
492 view->container->current.content_width,
493 view->container->current.content_height);
494 }
495 }
496
handle_request_fullscreen(struct wl_listener * listener,void * data)497 static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
498 struct sway_xwayland_view *xwayland_view =
499 wl_container_of(listener, xwayland_view, request_fullscreen);
500 struct sway_view *view = &xwayland_view->view;
501 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
502 if (!xsurface->mapped) {
503 return;
504 }
505 container_set_fullscreen(view->container, xsurface->fullscreen);
506
507 arrange_root();
508 transaction_commit_dirty();
509 }
510
handle_request_move(struct wl_listener * listener,void * data)511 static void handle_request_move(struct wl_listener *listener, void *data) {
512 struct sway_xwayland_view *xwayland_view =
513 wl_container_of(listener, xwayland_view, request_move);
514 struct sway_view *view = &xwayland_view->view;
515 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
516 if (!xsurface->mapped) {
517 return;
518 }
519 if (!container_is_floating(view->container)) {
520 return;
521 }
522 struct sway_seat *seat = input_manager_current_seat();
523 seatop_begin_move_floating(seat, view->container);
524 }
525
handle_request_resize(struct wl_listener * listener,void * data)526 static void handle_request_resize(struct wl_listener *listener, void *data) {
527 struct sway_xwayland_view *xwayland_view =
528 wl_container_of(listener, xwayland_view, request_resize);
529 struct sway_view *view = &xwayland_view->view;
530 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
531 if (!xsurface->mapped) {
532 return;
533 }
534 if (!container_is_floating(view->container)) {
535 return;
536 }
537 struct wlr_xwayland_resize_event *e = data;
538 struct sway_seat *seat = input_manager_current_seat();
539 seatop_begin_resize_floating(seat, view->container, e->edges);
540 }
541
handle_request_activate(struct wl_listener * listener,void * data)542 static void handle_request_activate(struct wl_listener *listener, void *data) {
543 struct sway_xwayland_view *xwayland_view =
544 wl_container_of(listener, xwayland_view, request_activate);
545 struct sway_view *view = &xwayland_view->view;
546 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
547 if (!xsurface->mapped) {
548 return;
549 }
550 view_request_activate(view);
551
552 transaction_commit_dirty();
553 }
554
handle_set_title(struct wl_listener * listener,void * data)555 static void handle_set_title(struct wl_listener *listener, void *data) {
556 struct sway_xwayland_view *xwayland_view =
557 wl_container_of(listener, xwayland_view, set_title);
558 struct sway_view *view = &xwayland_view->view;
559 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
560 if (!xsurface->mapped) {
561 return;
562 }
563 view_update_title(view, false);
564 view_execute_criteria(view);
565 }
566
handle_set_class(struct wl_listener * listener,void * data)567 static void handle_set_class(struct wl_listener *listener, void *data) {
568 struct sway_xwayland_view *xwayland_view =
569 wl_container_of(listener, xwayland_view, set_class);
570 struct sway_view *view = &xwayland_view->view;
571 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
572 if (!xsurface->mapped) {
573 return;
574 }
575 view_execute_criteria(view);
576 }
577
handle_set_role(struct wl_listener * listener,void * data)578 static void handle_set_role(struct wl_listener *listener, void *data) {
579 struct sway_xwayland_view *xwayland_view =
580 wl_container_of(listener, xwayland_view, set_role);
581 struct sway_view *view = &xwayland_view->view;
582 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
583 if (!xsurface->mapped) {
584 return;
585 }
586 view_execute_criteria(view);
587 }
588
handle_set_window_type(struct wl_listener * listener,void * data)589 static void handle_set_window_type(struct wl_listener *listener, void *data) {
590 struct sway_xwayland_view *xwayland_view =
591 wl_container_of(listener, xwayland_view, set_window_type);
592 struct sway_view *view = &xwayland_view->view;
593 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
594 if (!xsurface->mapped) {
595 return;
596 }
597 view_execute_criteria(view);
598 }
599
handle_set_hints(struct wl_listener * listener,void * data)600 static void handle_set_hints(struct wl_listener *listener, void *data) {
601 struct sway_xwayland_view *xwayland_view =
602 wl_container_of(listener, xwayland_view, set_hints);
603 struct sway_view *view = &xwayland_view->view;
604 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
605 if (!xsurface->mapped) {
606 return;
607 }
608 if (!xsurface->hints_urgency && view->urgent_timer) {
609 // The view is in the timeout period. We'll ignore the request to
610 // unset urgency so that the view remains urgent until the timer clears
611 // it.
612 return;
613 }
614 if (view->allow_request_urgent) {
615 view_set_urgent(view, (bool)xsurface->hints_urgency);
616 }
617 }
618
view_from_wlr_xwayland_surface(struct wlr_xwayland_surface * xsurface)619 struct sway_view *view_from_wlr_xwayland_surface(
620 struct wlr_xwayland_surface *xsurface) {
621 return xsurface->data;
622 }
623
handle_xwayland_surface(struct wl_listener * listener,void * data)624 void handle_xwayland_surface(struct wl_listener *listener, void *data) {
625 struct wlr_xwayland_surface *xsurface = data;
626
627 if (xsurface->override_redirect) {
628 sway_log(SWAY_DEBUG, "New xwayland unmanaged surface");
629 create_unmanaged(xsurface);
630 return;
631 }
632
633 sway_log(SWAY_DEBUG, "New xwayland surface title='%s' class='%s'",
634 xsurface->title, xsurface->class);
635
636 struct sway_xwayland_view *xwayland_view =
637 calloc(1, sizeof(struct sway_xwayland_view));
638 if (!sway_assert(xwayland_view, "Failed to allocate view")) {
639 return;
640 }
641
642 view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);
643 xwayland_view->view.wlr_xwayland_surface = xsurface;
644
645 wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy);
646 xwayland_view->destroy.notify = handle_destroy;
647
648 wl_signal_add(&xsurface->events.request_configure,
649 &xwayland_view->request_configure);
650 xwayland_view->request_configure.notify = handle_request_configure;
651
652 wl_signal_add(&xsurface->events.request_fullscreen,
653 &xwayland_view->request_fullscreen);
654 xwayland_view->request_fullscreen.notify = handle_request_fullscreen;
655
656 wl_signal_add(&xsurface->events.request_activate,
657 &xwayland_view->request_activate);
658 xwayland_view->request_activate.notify = handle_request_activate;
659
660 wl_signal_add(&xsurface->events.request_move,
661 &xwayland_view->request_move);
662 xwayland_view->request_move.notify = handle_request_move;
663
664 wl_signal_add(&xsurface->events.request_resize,
665 &xwayland_view->request_resize);
666 xwayland_view->request_resize.notify = handle_request_resize;
667
668 wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title);
669 xwayland_view->set_title.notify = handle_set_title;
670
671 wl_signal_add(&xsurface->events.set_class, &xwayland_view->set_class);
672 xwayland_view->set_class.notify = handle_set_class;
673
674 wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role);
675 xwayland_view->set_role.notify = handle_set_role;
676
677 wl_signal_add(&xsurface->events.set_window_type,
678 &xwayland_view->set_window_type);
679 xwayland_view->set_window_type.notify = handle_set_window_type;
680
681 wl_signal_add(&xsurface->events.set_hints, &xwayland_view->set_hints);
682 xwayland_view->set_hints.notify = handle_set_hints;
683
684 wl_signal_add(&xsurface->events.set_decorations,
685 &xwayland_view->set_decorations);
686 xwayland_view->set_decorations.notify = handle_set_decorations;
687
688 wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap);
689 xwayland_view->unmap.notify = handle_unmap;
690
691 wl_signal_add(&xsurface->events.map, &xwayland_view->map);
692 xwayland_view->map.notify = handle_map;
693
694 xsurface->data = xwayland_view;
695 }
696
handle_xwayland_ready(struct wl_listener * listener,void * data)697 void handle_xwayland_ready(struct wl_listener *listener, void *data) {
698 struct sway_server *server =
699 wl_container_of(listener, server, xwayland_ready);
700 struct sway_xwayland *xwayland = &server->xwayland;
701
702 wlr_xwayland_set_scale(xwayland->wlr_xwayland, config->xwayland_scale);
703
704 xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL);
705 int err = xcb_connection_has_error(xcb_conn);
706 if (err) {
707 sway_log(SWAY_ERROR, "XCB connect failed: %d", err);
708 return;
709 }
710
711 xcb_intern_atom_cookie_t cookies[ATOM_LAST];
712 for (size_t i = 0; i < ATOM_LAST; i++) {
713 cookies[i] =
714 xcb_intern_atom(xcb_conn, 0, strlen(atom_map[i]), atom_map[i]);
715 }
716 for (size_t i = 0; i < ATOM_LAST; i++) {
717 xcb_generic_error_t *error = NULL;
718 xcb_intern_atom_reply_t *reply =
719 xcb_intern_atom_reply(xcb_conn, cookies[i], &error);
720 if (reply != NULL && error == NULL) {
721 xwayland->atoms[i] = reply->atom;
722 }
723 free(reply);
724
725 if (error != NULL) {
726 sway_log(SWAY_ERROR, "could not resolve atom %s, X11 error code %d",
727 atom_map[i], error->error_code);
728 free(error);
729 break;
730 }
731 }
732
733 xcb_disconnect(xcb_conn);
734 }
735