diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 172ecaedc4cb1d886f6c82c573839fe04adab4e5..ebc1fa3ba0f6bcfd4491809b656014bbbd4b1982 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -119,6 +119,12 @@ struct wlr_drag { bool started, dropped, cancelling; int32_t grab_touch_id, touch_id; // if WLR_DRAG_GRAB_TOUCH + // when sending to x11 + struct { + int16_t cache_x, cache_y; + bool waiting, cached; + } pos; + struct { struct wl_signal focus; struct wl_signal motion; // struct wlr_drag_motion_event diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 0759aa682dc1e10e74066e334fd0d8f2bc5974d8..772b7c89725871bd84d5a316ea56df74184c5e07 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -290,8 +290,18 @@ static void drag_handle_touch_up(struct wlr_seat_touch_grab *grab, return; } - if (drag->focus_client) { + if (drag->focus_client && drag->source->current_dnd_action && + drag->source->accepted) { drag_drop(drag, time); + } else { + if (drag->focus_client != drag->seat_client) { + wlr_data_source_dnd_drop(drag->source); + } + if (drag->source->impl->dnd_finish) { + // This will end the grab and free `drag` + wlr_data_source_destroy(drag->source); + return; + } } drag_destroy(drag); diff --git a/xwayland/selection/dnd.c b/xwayland/selection/dnd.c index 637262aeef7a94e69f0e37b125391435ee7d6e01..494876beb7493b0ca46c3cdcf132677d55ba4e32 100644 --- a/xwayland/selection/dnd.c +++ b/xwayland/selection/dnd.c @@ -194,6 +194,12 @@ int xwm_handle_selection_client_message(struct wlr_xwm *xwm, wlr_data_source_dnd_action(drag->source, action); + drag->pos.waiting = false; + if (drag->pos.cached) { + drag->pos.cached = false; + xwm_dnd_send_position(xwm, XCB_CURRENT_TIME, drag->pos.cache_x, drag->pos.cache_y); + } + wlr_log(WLR_DEBUG, "DND_STATUS window=%" PRIu32 " accepted=%d action=%d", target_window, accepted, action); return 1; @@ -285,6 +291,10 @@ static void xwm_set_drag_focus(struct wlr_xwm *xwm, struct wlr_xwayland_surface return; } + // clear pos flags + xwm->drag->pos.waiting = false; + xwm->drag->pos.cached = false; + if (xwm->drag_focus != NULL) { wlr_data_source_dnd_action(xwm->drag->source, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE); @@ -329,11 +339,21 @@ static void seat_handle_drag_motion(struct wl_listener *listener, void *data) { struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_drag_motion); struct wlr_drag_motion_event *event = data; struct wlr_xwayland_surface *surface = xwm->drag_focus; + struct wlr_drag *drag = xwm->drag; if (surface == NULL) { return; // No xwayland surface focused } + if (drag->pos.waiting) { + drag->pos.cache_x = (int16_t)event->sx; + drag->pos.cache_y = (int16_t)event->sy; + drag->pos.cached = true; + return; + } + + drag->pos.waiting = true; + xwm_dnd_send_position(xwm, event->time, surface->x + (int16_t)event->sx, surface->y + (int16_t)event->sy); } diff --git a/xwayland/server.c b/xwayland/server.c index 95157811cdd4ff53c8fdbc7a76778ecf64f17c81..89132d3fc27d6ce46be8cc0944914c0c69228f4e 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -97,6 +97,12 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server, server->options.force_xrandr_emulation = false; #endif + char *xauthority_file = getenv("XAUTHORITY"); + if (xauthority_file && *xauthority_file) { + argv[i++] = "-auth"; + argv[i++] = xauthority_file; + } + argv[i++] = NULL; assert(i < sizeof(argv) / sizeof(argv[0])); diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 764e05d4d18aa3ed767192f57301ead18d98a126..7d95ae9b097dd09e57cbfe3f70a7d4701f94d2ef 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -380,9 +380,13 @@ static void xwm_set_focus_window(struct wlr_xwm *xwm, } if (!xsurface) { + // XCB_POINTER_ROOT is described in xcb documentation but isn't + // actually defined in the headers. It's distinct from XCB_NONE + // (which disables keyboard input entirely and causes issues + // with keyboard grabs for e.g. popups). xcb_set_input_focus_checked(xwm->xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT, - XCB_NONE, XCB_CURRENT_TIME); + 1L /*XCB_POINTER_ROOT*/, XCB_CURRENT_TIME); return; } @@ -984,27 +988,7 @@ static const struct wlr_addon_interface surface_addon_impl = { .destroy = xwayland_surface_handle_addon_destroy, }; -static void xwayland_surface_associate(struct wlr_xwm *xwm, - struct wlr_xwayland_surface *xsurface, struct wlr_surface *surface) { - assert(xsurface->surface == NULL); - - wl_list_remove(&xsurface->unpaired_link); - wl_list_init(&xsurface->unpaired_link); - xsurface->surface_id = 0; - - xsurface->surface = surface; - wlr_addon_init(&xsurface->surface_addon, &surface->addons, NULL, &surface_addon_impl); - - xsurface->surface_commit.notify = xwayland_surface_handle_commit; - wl_signal_add(&surface->events.commit, &xsurface->surface_commit); - - xsurface->surface_map.notify = xwayland_surface_handle_map; - wl_signal_add(&surface->events.map, &xsurface->surface_map); - - xsurface->surface_unmap.notify = xwayland_surface_handle_unmap; - wl_signal_add(&surface->events.unmap, &xsurface->surface_unmap); - - // read all surface properties +static void read_all_surface_properties(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface) { const xcb_atom_t props[] = { XCB_ATOM_WM_CLASS, XCB_ATOM_WM_NAME, @@ -1036,6 +1020,29 @@ static void xwayland_surface_associate(struct wlr_xwm *xwm, read_surface_property(xwm, xsurface, props[i], reply); free(reply); } +} + +static void xwayland_surface_associate(struct wlr_xwm *xwm, + struct wlr_xwayland_surface *xsurface, struct wlr_surface *surface) { + assert(xsurface->surface == NULL); + + wl_list_remove(&xsurface->unpaired_link); + wl_list_init(&xsurface->unpaired_link); + xsurface->surface_id = 0; + + xsurface->surface = surface; + wlr_addon_init(&xsurface->surface_addon, &surface->addons, NULL, &surface_addon_impl); + + xsurface->surface_commit.notify = xwayland_surface_handle_commit; + wl_signal_add(&surface->events.commit, &xsurface->surface_commit); + + xsurface->surface_map.notify = xwayland_surface_handle_map; + wl_signal_add(&surface->events.map, &xsurface->surface_map); + + xsurface->surface_unmap.notify = xwayland_surface_handle_unmap; + wl_signal_add(&surface->events.unmap, &xsurface->surface_unmap); + + read_all_surface_properties(xwm, xsurface); wl_signal_emit_mutable(&xsurface->events.associate, NULL); } @@ -1188,6 +1195,7 @@ static void xwm_handle_map_request(struct wlr_xwm *xwm, return; } + read_all_surface_properties(xwm, xsurface); wlr_xwayland_surface_set_withdrawn(xsurface, false); wlr_xwayland_surface_restack(xsurface, NULL, XCB_STACK_MODE_BELOW); xcb_map_window(xwm->xcb_conn, ev->window); @@ -1715,7 +1723,7 @@ static void xwm_handle_focus_in(struct wlr_xwm *xwm, struct wlr_xwayland_surface *requested_focus = lookup_surface(xwm, ev->event); if (requested_focus && ((xwm->focus_surface && requested_focus->pid == xwm->focus_surface->pid) || requested_focus->override_redirect)) { - if (requested_focus != xwm->focus_surface) { + if (requested_focus->surface && (requested_focus != xwm->focus_surface)) { xwm_set_focus_window(xwm, requested_focus); } } else {