xwm: Fix selection if no seat present at startup

It's possible that there are no seats present at startup (especially with
the RDP backend, which creates and removes seats for connections), and
previously we'd just fail to set up XWayland cut and paste properly.

We should set up a listener and find a seat when one becomes available -
but we also need to switch seats if ours is removed.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
Co-authored-by: Hideyuki Nagase <hideyukn@microsoft.com>
This commit is contained in:
Derek Foreman 2022-08-12 10:55:01 -05:00 committed by Marius Vlad
parent 7344970552
commit a04fd99212
3 changed files with 68 additions and 7 deletions

View File

@ -716,13 +716,61 @@ weston_wm_set_selection(struct wl_listener *listener, void *data)
XCB_TIME_CURRENT_TIME);
}
static void
maybe_reassign_selection_seat(struct weston_wm *wm)
{
struct weston_seat *seat;
/* If we already have a seat, keep it */
if (!wl_list_empty(&wm->selection_listener.link))
return;
seat = weston_wm_pick_seat(wm);
if (!seat)
return;
wl_list_remove(&wm->selection_listener.link);
wl_list_remove(&wm->seat_destroy_listener.link);
wl_signal_add(&seat->selection_signal, &wm->selection_listener);
wl_signal_add(&seat->destroy_signal, &wm->seat_destroy_listener);
weston_wm_set_selection(&wm->selection_listener, seat);
}
static void
weston_wm_seat_created(struct wl_listener *listener, void *data)
{
struct weston_wm *wm =
container_of(listener, struct weston_wm, seat_create_listener);
maybe_reassign_selection_seat(wm);
}
static void
weston_wm_seat_destroyed(struct wl_listener *listener, void *data)
{
struct weston_wm *wm =
container_of(listener, struct weston_wm, seat_destroy_listener);
wl_list_remove(&wm->selection_listener.link);
wl_list_init(&wm->selection_listener.link);
wl_list_remove(&wm->seat_destroy_listener.link);
wl_list_init(&wm->seat_destroy_listener.link);
/* Try to pick another available seat to fall back to */
maybe_reassign_selection_seat(wm);
}
void
weston_wm_selection_init(struct weston_wm *wm)
{
struct weston_seat *seat;
uint32_t values[1], mask;
wl_list_init(&wm->selection_listener.link);
wl_list_init(&wm->seat_create_listener.link);
wl_list_init(&wm->seat_destroy_listener.link);
wm->selection_request.requestor = XCB_NONE;
@ -751,11 +799,20 @@ weston_wm_selection_init(struct weston_wm *wm)
xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
wm->atom.clipboard, mask);
seat = weston_wm_pick_seat(wm);
if (seat == NULL)
return;
/* Try to set up a selection listener for any existing seat - we
* have a clipboard manager that can copy a subset of available
* selections so they don't disappear when the client owning
* them quits, but to make this work we need to have a seat
* to hang the selection off.
*
* If we have no seat or lose our seat we need to make sure we
* eventually assign a new one, so we listen for seat creation
* and destruction.
*/
wm->selection_listener.notify = weston_wm_set_selection;
wl_signal_add(&seat->selection_signal, &wm->selection_listener);
weston_wm_set_selection(&wm->selection_listener, seat);
wm->seat_destroy_listener.notify = weston_wm_seat_destroyed;
wm->seat_create_listener.notify = weston_wm_seat_created;
wl_signal_add(&wm->server->compositor->seat_created_signal,
&wm->seat_create_listener);
maybe_reassign_selection_seat(wm);
}

View File

@ -2728,6 +2728,8 @@ weston_wm_destroy(struct weston_wm *wm)
theme_destroy(wm->theme);
xcb_disconnect(wm->conn);
wl_event_source_remove(wm->source);
wl_list_remove(&wm->seat_create_listener.link);
wl_list_remove(&wm->seat_destroy_listener.link);
wl_list_remove(&wm->selection_listener.link);
wl_list_remove(&wm->activate_listener.link);
wl_list_remove(&wm->kill_listener.link);

View File

@ -88,6 +88,8 @@ struct weston_wm {
int selection_property_set;
int flush_property_on_delete;
struct wl_listener selection_listener;
struct wl_listener seat_create_listener;
struct wl_listener seat_destroy_listener;
xcb_window_t dnd_window;
xcb_window_t dnd_owner;