diff options
Diffstat (limited to 'sway/desktop/xwayland.c')
-rw-r--r-- | sway/desktop/xwayland.c | 189 |
1 files changed, 134 insertions, 55 deletions
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index b3b1473d..65d4fcd4 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -69,16 +69,11 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { | |||
69 | surface->ly = xsurface->y; | 69 | surface->ly = xsurface->y; |
70 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true); | 70 | desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true); |
71 | 71 | ||
72 | if (!wlr_xwayland_surface_is_unmanaged(xsurface)) { | 72 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
73 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 73 | struct wlr_xwayland *xwayland = |
74 | struct wlr_xwayland *xwayland = | 74 | seat->input->server->xwayland.wlr_xwayland; |
75 | seat->input->server->xwayland.wlr_xwayland; | 75 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); |
76 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | 76 | seat_set_focus_surface(seat, xsurface->surface, false); |
77 | seat_set_focus_surface(seat, xsurface->surface); | ||
78 | } | ||
79 | |||
80 | // TODO: we don't send surface enter/leave events to xwayland unmanaged | ||
81 | // surfaces, but xwayland doesn't support HiDPI anyway | ||
82 | } | 77 | } |
83 | 78 | ||
84 | static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | 79 | static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { |
@@ -89,18 +84,16 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
89 | wl_list_remove(&surface->link); | 84 | wl_list_remove(&surface->link); |
90 | wl_list_remove(&surface->commit.link); | 85 | wl_list_remove(&surface->commit.link); |
91 | 86 | ||
92 | if (!wlr_xwayland_surface_is_unmanaged(xsurface)) { | 87 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
93 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 88 | if (seat->wlr_seat->keyboard_state.focused_surface == |
94 | if (seat->wlr_seat->keyboard_state.focused_surface == | 89 | xsurface->surface) { |
95 | xsurface->surface) { | 90 | // Restore focus |
96 | // Restore focus | 91 | struct sway_container *previous = |
97 | struct sway_container *previous = | 92 | seat_get_focus_inactive(seat, &root_container); |
98 | seat_get_focus_inactive(seat, &root_container); | 93 | if (previous) { |
99 | if (previous) { | 94 | // Hack to get seat to re-focus the return value of get_focus |
100 | // Hack to get seat to re-focus the return value of get_focus | 95 | seat_set_focus(seat, previous->parent); |
101 | seat_set_focus(seat, previous->parent); | 96 | seat_set_focus(seat, previous); |
102 | seat_set_focus(seat, previous); | ||
103 | } | ||
104 | } | 97 | } |
105 | } | 98 | } |
106 | } | 99 | } |
@@ -119,7 +112,7 @@ static struct sway_xwayland_unmanaged *create_unmanaged( | |||
119 | struct sway_xwayland_unmanaged *surface = | 112 | struct sway_xwayland_unmanaged *surface = |
120 | calloc(1, sizeof(struct sway_xwayland_unmanaged)); | 113 | calloc(1, sizeof(struct sway_xwayland_unmanaged)); |
121 | if (surface == NULL) { | 114 | if (surface == NULL) { |
122 | wlr_log(L_ERROR, "Allocation failed"); | 115 | wlr_log(WLR_ERROR, "Allocation failed"); |
123 | return NULL; | 116 | return NULL; |
124 | } | 117 | } |
125 | 118 | ||
@@ -246,6 +239,14 @@ static bool wants_floating(struct sway_view *view) { | |||
246 | return false; | 239 | return false; |
247 | } | 240 | } |
248 | 241 | ||
242 | static bool has_client_side_decorations(struct sway_view *view) { | ||
243 | if (xwayland_view_from_view(view) == NULL) { | ||
244 | return false; | ||
245 | } | ||
246 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; | ||
247 | return surface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL; | ||
248 | } | ||
249 | |||
249 | static void _close(struct sway_view *view) { | 250 | static void _close(struct sway_view *view) { |
250 | if (xwayland_view_from_view(view) == NULL) { | 251 | if (xwayland_view_from_view(view) == NULL) { |
251 | return; | 252 | return; |
@@ -269,6 +270,7 @@ static const struct sway_view_impl view_impl = { | |||
269 | .set_tiled = set_tiled, | 270 | .set_tiled = set_tiled, |
270 | .set_fullscreen = set_fullscreen, | 271 | .set_fullscreen = set_fullscreen, |
271 | .wants_floating = wants_floating, | 272 | .wants_floating = wants_floating, |
273 | .has_client_side_decorations = has_client_side_decorations, | ||
272 | .close = _close, | 274 | .close = _close, |
273 | .destroy = destroy, | 275 | .destroy = destroy, |
274 | }; | 276 | }; |
@@ -278,15 +280,42 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
278 | wl_container_of(listener, xwayland_view, commit); | 280 | wl_container_of(listener, xwayland_view, commit); |
279 | struct sway_view *view = &xwayland_view->view; | 281 | struct sway_view *view = &xwayland_view->view; |
280 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 282 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
281 | struct wlr_surface_state *surface_state = xsurface->surface->current; | 283 | struct wlr_surface_state *surface_state = &xsurface->surface->current; |
282 | 284 | ||
283 | if (view->swayc->instructions->length) { | 285 | if (view->swayc->instructions->length) { |
284 | transaction_notify_view_ready_by_size(view, | 286 | transaction_notify_view_ready_by_size(view, |
285 | surface_state->width, surface_state->height); | 287 | surface_state->width, surface_state->height); |
288 | } else if (container_is_floating(view->swayc)) { | ||
289 | view_update_size(view, surface_state->width, surface_state->height); | ||
286 | } | 290 | } |
291 | |||
287 | view_damage_from(view); | 292 | view_damage_from(view); |
288 | } | 293 | } |
289 | 294 | ||
295 | static void handle_destroy(struct wl_listener *listener, void *data) { | ||
296 | struct sway_xwayland_view *xwayland_view = | ||
297 | wl_container_of(listener, xwayland_view, destroy); | ||
298 | struct sway_view *view = &xwayland_view->view; | ||
299 | |||
300 | if (view->surface) { | ||
301 | view_unmap(view); | ||
302 | wl_list_remove(&xwayland_view->commit.link); | ||
303 | } | ||
304 | |||
305 | wl_list_remove(&xwayland_view->destroy.link); | ||
306 | wl_list_remove(&xwayland_view->request_configure.link); | ||
307 | wl_list_remove(&xwayland_view->request_fullscreen.link); | ||
308 | wl_list_remove(&xwayland_view->request_move.link); | ||
309 | wl_list_remove(&xwayland_view->request_resize.link); | ||
310 | wl_list_remove(&xwayland_view->set_title.link); | ||
311 | wl_list_remove(&xwayland_view->set_class.link); | ||
312 | wl_list_remove(&xwayland_view->set_window_type.link); | ||
313 | wl_list_remove(&xwayland_view->set_hints.link); | ||
314 | wl_list_remove(&xwayland_view->map.link); | ||
315 | wl_list_remove(&xwayland_view->unmap.link); | ||
316 | view_destroy(&xwayland_view->view); | ||
317 | } | ||
318 | |||
290 | static void handle_unmap(struct wl_listener *listener, void *data) { | 319 | static void handle_unmap(struct wl_listener *listener, void *data) { |
291 | struct sway_xwayland_view *xwayland_view = | 320 | struct sway_xwayland_view *xwayland_view = |
292 | wl_container_of(listener, xwayland_view, unmap); | 321 | wl_container_of(listener, xwayland_view, unmap); |
@@ -307,6 +336,15 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
307 | struct wlr_xwayland_surface *xsurface = data; | 336 | struct wlr_xwayland_surface *xsurface = data; |
308 | struct sway_view *view = &xwayland_view->view; | 337 | struct sway_view *view = &xwayland_view->view; |
309 | 338 | ||
339 | if (xsurface->override_redirect) { | ||
340 | // This window used not to have the override redirect flag and has it | ||
341 | // now. Switch to unmanaged. | ||
342 | handle_destroy(&xwayland_view->destroy, view); | ||
343 | struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface); | ||
344 | unmanaged_handle_map(&unmanaged->map, xsurface); | ||
345 | return; | ||
346 | } | ||
347 | |||
310 | view->natural_width = xsurface->width; | 348 | view->natural_width = xsurface->width; |
311 | view->natural_height = xsurface->height; | 349 | view->natural_height = xsurface->height; |
312 | 350 | ||
@@ -321,31 +359,11 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
321 | if (xsurface->fullscreen) { | 359 | if (xsurface->fullscreen) { |
322 | view_set_fullscreen(view, true); | 360 | view_set_fullscreen(view, true); |
323 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 361 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); |
324 | arrange_and_commit(ws); | 362 | arrange_windows(ws); |
325 | } else { | 363 | } else { |
326 | arrange_and_commit(view->swayc->parent); | 364 | arrange_windows(view->swayc->parent); |
327 | } | ||
328 | } | ||
329 | |||
330 | static void handle_destroy(struct wl_listener *listener, void *data) { | ||
331 | struct sway_xwayland_view *xwayland_view = | ||
332 | wl_container_of(listener, xwayland_view, destroy); | ||
333 | struct sway_view *view = &xwayland_view->view; | ||
334 | |||
335 | if (view->surface) { | ||
336 | view_unmap(view); | ||
337 | wl_list_remove(&xwayland_view->commit.link); | ||
338 | } | 365 | } |
339 | 366 | transaction_commit_dirty(); | |
340 | wl_list_remove(&xwayland_view->destroy.link); | ||
341 | wl_list_remove(&xwayland_view->request_configure.link); | ||
342 | wl_list_remove(&xwayland_view->request_fullscreen.link); | ||
343 | wl_list_remove(&xwayland_view->set_title.link); | ||
344 | wl_list_remove(&xwayland_view->set_class.link); | ||
345 | wl_list_remove(&xwayland_view->set_window_type.link); | ||
346 | wl_list_remove(&xwayland_view->map.link); | ||
347 | wl_list_remove(&xwayland_view->unmap.link); | ||
348 | view_destroy(&xwayland_view->view); | ||
349 | } | 367 | } |
350 | 368 | ||
351 | static void handle_request_configure(struct wl_listener *listener, void *data) { | 369 | static void handle_request_configure(struct wl_listener *listener, void *data) { |
@@ -379,8 +397,40 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
379 | } | 397 | } |
380 | view_set_fullscreen(view, xsurface->fullscreen); | 398 | view_set_fullscreen(view, xsurface->fullscreen); |
381 | 399 | ||
382 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 400 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); |
383 | arrange_and_commit(ws); | 401 | arrange_windows(output); |
402 | transaction_commit_dirty(); | ||
403 | } | ||
404 | |||
405 | static void handle_request_move(struct wl_listener *listener, void *data) { | ||
406 | struct sway_xwayland_view *xwayland_view = | ||
407 | wl_container_of(listener, xwayland_view, request_move); | ||
408 | struct sway_view *view = &xwayland_view->view; | ||
409 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
410 | if (!xsurface->mapped) { | ||
411 | return; | ||
412 | } | ||
413 | if (!container_is_floating(view->swayc)) { | ||
414 | return; | ||
415 | } | ||
416 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
417 | seat_begin_move(seat, view->swayc, seat->last_button); | ||
418 | } | ||
419 | |||
420 | static void handle_request_resize(struct wl_listener *listener, void *data) { | ||
421 | struct sway_xwayland_view *xwayland_view = | ||
422 | wl_container_of(listener, xwayland_view, request_resize); | ||
423 | struct sway_view *view = &xwayland_view->view; | ||
424 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
425 | if (!xsurface->mapped) { | ||
426 | return; | ||
427 | } | ||
428 | if (!container_is_floating(view->swayc)) { | ||
429 | return; | ||
430 | } | ||
431 | struct wlr_xwayland_resize_event *e = data; | ||
432 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
433 | seat_begin_resize(seat, view->swayc, seat->last_button, e->edges); | ||
384 | } | 434 | } |
385 | 435 | ||
386 | static void handle_set_title(struct wl_listener *listener, void *data) { | 436 | static void handle_set_title(struct wl_listener *listener, void *data) { |
@@ -417,6 +467,25 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) { | |||
417 | view_execute_criteria(view); | 467 | view_execute_criteria(view); |
418 | } | 468 | } |
419 | 469 | ||
470 | static void handle_set_hints(struct wl_listener *listener, void *data) { | ||
471 | struct sway_xwayland_view *xwayland_view = | ||
472 | wl_container_of(listener, xwayland_view, set_hints); | ||
473 | struct sway_view *view = &xwayland_view->view; | ||
474 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
475 | if (!xsurface->mapped) { | ||
476 | return; | ||
477 | } | ||
478 | if (!xsurface->hints_urgency && view->urgent_timer) { | ||
479 | // The view is is in the timeout period. We'll ignore the request to | ||
480 | // unset urgency so that the view remains urgent until the timer clears | ||
481 | // it. | ||
482 | return; | ||
483 | } | ||
484 | if (view->allow_request_urgent) { | ||
485 | view_set_urgent(view, (bool)xsurface->hints_urgency); | ||
486 | } | ||
487 | } | ||
488 | |||
420 | struct sway_view *view_from_wlr_xwayland_surface( | 489 | struct sway_view *view_from_wlr_xwayland_surface( |
421 | struct wlr_xwayland_surface *xsurface) { | 490 | struct wlr_xwayland_surface *xsurface) { |
422 | return xsurface->data; | 491 | return xsurface->data; |
@@ -427,14 +496,13 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
427 | xwayland_surface); | 496 | xwayland_surface); |
428 | struct wlr_xwayland_surface *xsurface = data; | 497 | struct wlr_xwayland_surface *xsurface = data; |
429 | 498 | ||
430 | if (wlr_xwayland_surface_is_unmanaged(xsurface) || | 499 | if (xsurface->override_redirect) { |
431 | xsurface->override_redirect) { | 500 | wlr_log(WLR_DEBUG, "New xwayland unmanaged surface"); |
432 | wlr_log(L_DEBUG, "New xwayland unmanaged surface"); | ||
433 | create_unmanaged(xsurface); | 501 | create_unmanaged(xsurface); |
434 | return; | 502 | return; |
435 | } | 503 | } |
436 | 504 | ||
437 | wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'", | 505 | wlr_log(WLR_DEBUG, "New xwayland surface title='%s' class='%s'", |
438 | xsurface->title, xsurface->class); | 506 | xsurface->title, xsurface->class); |
439 | 507 | ||
440 | struct sway_xwayland_view *xwayland_view = | 508 | struct sway_xwayland_view *xwayland_view = |
@@ -457,6 +525,14 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
457 | &xwayland_view->request_fullscreen); | 525 | &xwayland_view->request_fullscreen); |
458 | xwayland_view->request_fullscreen.notify = handle_request_fullscreen; | 526 | xwayland_view->request_fullscreen.notify = handle_request_fullscreen; |
459 | 527 | ||
528 | wl_signal_add(&xsurface->events.request_move, | ||
529 | &xwayland_view->request_move); | ||
530 | xwayland_view->request_move.notify = handle_request_move; | ||
531 | |||
532 | wl_signal_add(&xsurface->events.request_resize, | ||
533 | &xwayland_view->request_resize); | ||
534 | xwayland_view->request_resize.notify = handle_request_resize; | ||
535 | |||
460 | wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title); | 536 | wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title); |
461 | xwayland_view->set_title.notify = handle_set_title; | 537 | xwayland_view->set_title.notify = handle_set_title; |
462 | 538 | ||
@@ -467,6 +543,9 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
467 | &xwayland_view->set_window_type); | 543 | &xwayland_view->set_window_type); |
468 | xwayland_view->set_window_type.notify = handle_set_window_type; | 544 | xwayland_view->set_window_type.notify = handle_set_window_type; |
469 | 545 | ||
546 | wl_signal_add(&xsurface->events.set_hints, &xwayland_view->set_hints); | ||
547 | xwayland_view->set_hints.notify = handle_set_hints; | ||
548 | |||
470 | wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); | 549 | wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); |
471 | xwayland_view->unmap.notify = handle_unmap; | 550 | xwayland_view->unmap.notify = handle_unmap; |
472 | 551 | ||
@@ -484,7 +563,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) { | |||
484 | xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL); | 563 | xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL); |
485 | int err = xcb_connection_has_error(xcb_conn); | 564 | int err = xcb_connection_has_error(xcb_conn); |
486 | if (err) { | 565 | if (err) { |
487 | wlr_log(L_ERROR, "XCB connect failed: %d", err); | 566 | wlr_log(WLR_ERROR, "XCB connect failed: %d", err); |
488 | return; | 567 | return; |
489 | } | 568 | } |
490 | 569 | ||
@@ -503,7 +582,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) { | |||
503 | free(reply); | 582 | free(reply); |
504 | 583 | ||
505 | if (error != NULL) { | 584 | if (error != NULL) { |
506 | wlr_log(L_ERROR, "could not resolve atom %s, X11 error code %d", | 585 | wlr_log(WLR_ERROR, "could not resolve atom %s, X11 error code %d", |
507 | atom_map[i], error->error_code); | 586 | atom_map[i], error->error_code); |
508 | free(error); | 587 | free(error); |
509 | break; | 588 | break; |