History

video/out/wayland_common: fix dnd with focus follow mouse

Whenever mpv window gains focus, a new data offer is sent for the selection. However, mpv currently treats it the same as dnd data offers, which results in wrong handling. One bug which results from this is when focus follow mouse is enabled, dropping the dnd file results in the window being focused and selection offer being sent, freeing the existing dnd offer. This results in dnd being broken on at least GTK3. Fix this by separating selection and dnd offer handling. Since there is no way to know whether an offer introduced by data_device_handle_data_offer is a selection or dnd offer, make it pending, and move them once the identity is confirmed.

nanahi committed 2 years ago

Commit 70e02e71 parent eb0c4b92 files · +35 −23Browse files

Unified · Split

2 files
  1. video/out/wayland_common.c +32 −22
  2. video/out/wayland_common.h +3 −1
video/out/wayland_common.c+32−22
@@ -259,6 +259,7 @@ static void set_surface_scaling(struct vo_wayland_state *wl); · 258 unmodified lines
259259 static void update_output_scaling(struct vo_wayland_state *wl);
260260 static void update_output_geometry(struct vo_wayland_state *wl, struct mp_rect old_geometry,
261261 struct mp_rect old_output_geometry);
262+static void destroy_offer(struct vo_wayland_data_offer *o);
262263
263264 /* Wayland listener boilerplate */
264265 static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
@@ -696,12 +697,12 @@ static void data_offer_handle_offer(void *data, struct wl_data_offer *offer, · 431 unmodified lines
696697 {
697698 struct vo_wayland_seat *s = data;
698699 struct vo_wayland_state *wl = s->wl;
699− struct vo_wayland_data_offer *o = wl->dnd_offer;
700+ struct vo_wayland_data_offer *o = wl->pending_offer;
700701 int score = mp_event_get_mime_type_score(wl->vo->input_ctx, mime_type);
701− if (score > o->mime_score && wl->opts->drag_and_drop != -2) {
702+ if (o->offer && score > o->mime_score && wl->opts->drag_and_drop != -2) {
702703 o->mime_score = score;
703704 talloc_replace(wl, o->mime_type, mime_type);
704− MP_VERBOSE(wl, "Given DND offer with mime type %s\n", o->mime_type);
705+ MP_VERBOSE(wl, "Given data offer with mime type %s\n", o->mime_type);
705706 }
706707 }
707708
@@ -743,9 +744,8 @@ static void data_device_handle_data_offer(void *data, struct wl_data_device *wl_ · 35 unmodified lines
743744 {
744745 struct vo_wayland_seat *s = data;
745746 struct vo_wayland_state *wl = s->wl;
746− struct vo_wayland_data_offer *o = wl->dnd_offer;
747− if (o->offer)
748− wl_data_offer_destroy(o->offer);
747+ struct vo_wayland_data_offer *o = wl->pending_offer;
748+ destroy_offer(o);
749749
750750 o->offer = id;
751751 wl_data_offer_add_listener(id, &data_offer_listener, s);
@@ -758,12 +758,16 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_ddev, · 6 unmodified lines
758758 {
759759 struct vo_wayland_seat *s = data;
760760 struct vo_wayland_state *wl = s->wl;
761− struct vo_wayland_data_offer *o = wl->dnd_offer;
761+ struct vo_wayland_data_offer *o = wl->pending_offer;
762762 if (o->offer != id) {
763763 MP_FATAL(wl, "DND offer ID mismatch!\n");
764764 return;
765765 }
766766
767+ assert(!wl->dnd_offer->offer);
768+ *wl->dnd_offer = *wl->pending_offer;
769+ *wl->pending_offer = (struct vo_wayland_data_offer){.fd = -1};
770+ o = wl->dnd_offer;
767771 if (wl->opts->drag_and_drop != -2) {
768772 wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
769773 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
@@ -831,14 +835,18 @@ static void data_device_handle_selection(void *data, struct wl_data_device *wl_d · 61 unmodified lines
831835 {
832836 struct vo_wayland_seat *s = data;
833837 struct vo_wayland_state *wl = s->wl;
834− struct vo_wayland_data_offer *o = wl->dnd_offer;
835−
836− if (o->offer) {
837− wl_data_offer_destroy(o->offer);
838− o->offer = NULL;
839− MP_VERBOSE(wl, "Received a new DND offer. Releasing the previous offer.\n");
838+ struct vo_wayland_data_offer *o = wl->pending_offer;
839+ if (o->offer != id) {
840+ MP_FATAL(wl, "Selection offer ID mismatch!\n");
841+ return;
840842 }
841843
844+ if (wl->selection_offer->offer) {
845+ destroy_offer(wl->selection_offer);
846+ MP_VERBOSE(wl, "Received a new selection offer. Releasing the previous offer.\n");
847+ }
848+ *wl->selection_offer = *wl->pending_offer;
849+ *wl->pending_offer = (struct vo_wayland_data_offer){.fd = -1};
842850 }
843851
844852 static const struct wl_data_device_listener data_device_listener = {
@@ -1690,7 +1698,7 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id · 845 unmodified lines
16901698
16911699 if (!strcmp(interface, wl_data_device_manager_interface.name) && (ver >= 3) && found++) {
16921700 ver = 3;
1693− wl->dnd_devman = wl_registry_bind(reg, id, &wl_data_device_manager_interface, ver);
1701+ wl->devman = wl_registry_bind(reg, id, &wl_data_device_manager_interface, ver);
16941702 }
16951703
16961704 if (!strcmp(interface, wl_output_interface.name) && (ver >= 2) && found++) {
@@ -1898,15 +1906,13 @@ static void check_dnd_fd(struct vo_wayland_state *wl) · 201 unmodified lines
18981906 }
18991907
19001908 talloc_free(file_list.start);
1901− free_offer_data(wl->dnd_offer);
1909+ destroy_offer(o);
19021910 }
19031911
19041912 if (fdp.revents & (POLLIN | POLLERR | POLLHUP)) {
19051913 if (o->action >= 0)
19061914 MP_VERBOSE(wl, "DND aborted (hang up or error)\n");
1907− free_offer_data(wl->dnd_offer);
1908− close(o->fd);
1909− o->fd = -1;
1915+ destroy_offer(o);
19101916 }
19111917 }
19121918
@@ -3058,7 +3064,9 @@ bool vo_wayland_init(struct vo *vo) · 1145 unmodified lines
30583064 .scaling = WAYLAND_SCALE_FACTOR,
30593065 .wakeup_pipe = {-1, -1},
30603066 .display_fd = -1,
3067+ .pending_offer = talloc_zero(wl, struct vo_wayland_data_offer),
30613068 .dnd_offer = talloc_zero(wl, struct vo_wayland_data_offer),
3069+ .selection_offer = talloc_zero(wl, struct vo_wayland_data_offer),
30623070 .cursor_visible = true,
30633071 .opts_cache = m_config_cache_alloc(wl, vo->global, &vo_sub_opts),
30643072 };
@@ -3148,10 +3156,10 @@ bool vo_wayland_init(struct vo *vo) · 83 unmodified lines
31483156 }
31493157 #endif
31503158
3151− if (wl->dnd_devman) {
3159+ if (wl->devman) {
31523160 struct vo_wayland_seat *seat;
31533161 wl_list_for_each(seat, &wl->seat_list, link) {
3154− seat->dnd_ddev = wl_data_device_manager_get_data_device(wl->dnd_devman, seat->seat);
3162+ seat->dnd_ddev = wl_data_device_manager_get_data_device(wl->devman, seat->seat);
31553163 wl_data_device_add_listener(seat->dnd_ddev, &data_device_listener, seat);
31563164 }
31573165 } else {
@@ -3287,7 +3295,9 @@ void vo_wayland_uninit(struct vo *vo) · 129 unmodified lines
32873295 if (!wl)
32883296 return;
32893297
3298+ destroy_offer(wl->pending_offer);
32903299 destroy_offer(wl->dnd_offer);
3300+ destroy_offer(wl->selection_offer);
32913301
32923302 mp_input_put_key(wl->vo->input_ctx, MP_INPUT_RELEASE_ALL);
32933303
@@ -3326,8 +3336,8 @@ void vo_wayland_uninit(struct vo *vo) · 32 unmodified lines
33263336 if (wl->content_type_manager)
33273337 wp_content_type_manager_v1_destroy(wl->content_type_manager);
33283338
3329− if (wl->dnd_devman)
3330− wl_data_device_manager_destroy(wl->dnd_devman);
3339+ if (wl->devman)
3340+ wl_data_device_manager_destroy(wl->devman);
33313341
33323342 if (wl->fback_pool)
33333343 clean_feedback_pool(wl->fback_pool);
video/out/wayland_common.h+3−1
@@ -162,8 +162,10 @@ struct vo_wayland_state { · 161 unmodified lines
162162 struct xkb_context *xkb_context;
163163
164164 /* Data offer */
165− struct wl_data_device_manager *dnd_devman;
165+ struct wl_data_device_manager *devman;
166+ struct vo_wayland_data_offer *pending_offer;
166167 struct vo_wayland_data_offer *dnd_offer;
168+ struct vo_wayland_data_offer *selection_offer;
167169
168170 /* Cursor */
169171 struct wl_cursor_theme *cursor_theme;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t