@@ -57,9 +57,10 @@ struct _MetaXWaylandDnd
5757 Time client_message_timestamp ;
5858 MetaWaylandDataSource * source ; /* owned by MetaWaylandDataDevice */
5959 MetaWaylandSurface * focus_surface ;
60- Window dnd_window ; /* Mutter -internal window, acts as peer on wayland drop sites */
60+ Window dnd_window [ 2 ] ; /* Muffin -internal windows, act as peers on wayland drop sites */
6161 Window dnd_dest ; /* X11 drag dest window */
6262 guint32 last_motion_time ;
63+ int current_dnd_window ;
6364};
6465
6566enum
@@ -133,6 +134,90 @@ atom_to_action (Atom atom)
133134 return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE ;
134135}
135136
137+ static Window
138+ current_dnd_window (MetaXWaylandDnd * dnd )
139+ {
140+ return dnd -> dnd_window [dnd -> current_dnd_window ];
141+ }
142+
143+ /* X11 drag sources only emit XdndLeave/XdndEnter when the target window
144+ * changes, so moving between two wayland windows has to hand the source a
145+ * different peer window or it never learns the drop site changed.
146+ */
147+ static Window
148+ next_dnd_window (MetaXWaylandDnd * dnd )
149+ {
150+ dnd -> current_dnd_window =
151+ (dnd -> current_dnd_window + 1 ) % G_N_ELEMENTS (dnd -> dnd_window );
152+
153+ return current_dnd_window (dnd );
154+ }
155+
156+ static void
157+ create_dnd_windows (MetaXWaylandDnd * dnd ,
158+ Display * xdisplay )
159+ {
160+ XSetWindowAttributes attributes ;
161+ guint32 version = XDND_VERSION ;
162+ guint i ;
163+
164+ attributes .event_mask = PropertyChangeMask | SubstructureNotifyMask ;
165+ attributes .override_redirect = True ;
166+
167+ for (i = 0 ; i < G_N_ELEMENTS (dnd -> dnd_window ); i ++ )
168+ {
169+ dnd -> dnd_window [i ] =
170+ XCreateWindow (xdisplay ,
171+ gdk_x11_window_get_xid (gdk_get_default_root_window ()),
172+ -1 , -1 , 1 , 1 ,
173+ 0 , /* border width */
174+ 0 , /* depth */
175+ InputOnly , /* class */
176+ CopyFromParent , /* visual */
177+ CWEventMask | CWOverrideRedirect ,
178+ & attributes );
179+
180+ XChangeProperty (xdisplay , dnd -> dnd_window [i ],
181+ xdnd_atoms [ATOM_DND_AWARE ],
182+ XA_ATOM , 32 , PropModeReplace ,
183+ (guchar * ) & version , 1 );
184+ }
185+ }
186+
187+ static void
188+ destroy_dnd_windows (MetaXWaylandDnd * dnd ,
189+ Display * xdisplay )
190+ {
191+ guint i ;
192+
193+ for (i = 0 ; i < G_N_ELEMENTS (dnd -> dnd_window ); i ++ )
194+ {
195+ XDestroyWindow (xdisplay , dnd -> dnd_window [i ]);
196+ dnd -> dnd_window [i ] = None ;
197+ }
198+ }
199+
200+ static void
201+ hide_dnd_window (MetaXWaylandDnd * dnd ,
202+ Display * xdisplay ,
203+ int index )
204+ {
205+ g_assert (index < (int ) G_N_ELEMENTS (dnd -> dnd_window ));
206+
207+ XMoveResizeWindow (xdisplay , dnd -> dnd_window [index ], -1 , -1 , 1 , 1 );
208+ XUnmapWindow (xdisplay , dnd -> dnd_window [index ]);
209+ }
210+
211+ static void
212+ hide_all_dnd_windows (MetaXWaylandDnd * dnd ,
213+ Display * xdisplay )
214+ {
215+ guint i ;
216+
217+ for (i = 0 ; i < G_N_ELEMENTS (dnd -> dnd_window ); i ++ )
218+ hide_dnd_window (dnd , xdisplay , i );
219+ }
220+
136221static void
137222xdnd_send_enter (MetaXWaylandDnd * dnd ,
138223 Window dest )
@@ -295,7 +380,7 @@ xdnd_send_finished (MetaXWaylandDnd *dnd,
295380 xev .xclient .format = 32 ;
296381 xev .xclient .window = dest ;
297382
298- xev .xclient .data .l [0 ] = dnd -> dnd_window ;
383+ xev .xclient .data .l [0 ] = current_dnd_window ( dnd ) ;
299384
300385 if (accepted )
301386 {
@@ -325,7 +410,7 @@ xdnd_send_status (MetaXWaylandDnd *dnd,
325410 xev .xclient .format = 32 ;
326411 xev .xclient .window = dest ;
327412
328- xev .xclient .data .l [0 ] = dnd -> dnd_window ;
413+ xev .xclient .data .l [0 ] = current_dnd_window ( dnd ) ;
329414 xev .xclient .data .l [1 ] = 1 << 1 ; /* Bit 2: dest wants XdndPosition messages */
330415 xev .xclient .data .l [4 ] = action_to_atom (action );
331416
@@ -357,8 +442,7 @@ meta_xwayland_end_dnd_grab (MetaWaylandDataDevice *data_device,
357442 meta_wayland_data_device_end_drag (data_device );
358443 }
359444
360- XMoveResizeWindow (xdisplay , dnd -> dnd_window , -1 , -1 , 1 , 1 );
361- XUnmapWindow (xdisplay , dnd -> dnd_window );
445+ hide_all_dnd_windows (dnd , xdisplay );
362446}
363447
364448static void
@@ -581,6 +665,7 @@ meta_xwayland_data_source_fetch_mimetype_list (MetaWaylandDataSource *source,
581665{
582666 MetaWaylandDataSourceXWayland * source_xwayland =
583667 META_WAYLAND_DATA_SOURCE_XWAYLAND (source );
668+ MetaX11Display * x11_display = meta_get_display ()-> x11_display ;
584669 Display * xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
585670 gulong nitems_ret , bytes_after_ret , i ;
586671 Atom * atoms , type_ret , utf8_string ;
@@ -591,17 +676,28 @@ meta_xwayland_data_source_fetch_mimetype_list (MetaWaylandDataSource *source,
591676 if (source_mime_types -> size != 0 )
592677 return TRUE;
593678
679+ /* The drag source can be gone by the time we get here, and an untrapped
680+ * BadWindow is fatal to the compositor. */
681+ meta_x11_error_trap_push (x11_display );
682+
594683 utf8_string = gdk_x11_get_xatom_by_name ("UTF8_STRING" );
595- XGetWindowProperty (xdisplay , window , prop ,
596- 0 , /* offset */
597- 0x1fffffff , /* length */
598- False , /* delete */
599- AnyPropertyType ,
600- & type_ret ,
601- & format_ret ,
602- & nitems_ret ,
603- & bytes_after_ret ,
604- (guchar * * ) & atoms );
684+ if (XGetWindowProperty (xdisplay , window , prop ,
685+ 0 , /* offset */
686+ 0x1fffffff , /* length */
687+ False , /* delete */
688+ AnyPropertyType ,
689+ & type_ret ,
690+ & format_ret ,
691+ & nitems_ret ,
692+ & bytes_after_ret ,
693+ (guchar * * ) & atoms ) != Success )
694+ {
695+ meta_x11_error_trap_pop (x11_display );
696+ return FALSE;
697+ }
698+
699+ if (meta_x11_error_trap_pop_with_return (x11_display ) != Success )
700+ return FALSE;
605701
606702 if (nitems_ret == 0 || type_ret != XA_ATOM )
607703 {
@@ -668,17 +764,21 @@ repick_drop_surface (MetaWaylandCompositor *compositor,
668764 if (focus_window &&
669765 focus_window -> client_type == META_WINDOW_CLIENT_TYPE_WAYLAND )
670766 {
671- XMapRaised (xdisplay , dnd -> dnd_window );
672- XMoveResizeWindow (xdisplay , dnd -> dnd_window ,
767+ Window dnd_window ;
768+
769+ hide_dnd_window (dnd , xdisplay , dnd -> current_dnd_window );
770+ dnd_window = next_dnd_window (dnd );
771+
772+ XMapRaised (xdisplay , dnd_window );
773+ XMoveResizeWindow (xdisplay , dnd_window ,
673774 focus_window -> rect .x ,
674775 focus_window -> rect .y ,
675776 focus_window -> rect .width ,
676777 focus_window -> rect .height );
677778 }
678779 else
679780 {
680- XMoveResizeWindow (xdisplay , dnd -> dnd_window , -1 , -1 , 1 , 1 );
681- XUnmapWindow (xdisplay , dnd -> dnd_window );
781+ hide_all_dnd_windows (dnd , xdisplay );
682782 }
683783}
684784
@@ -945,8 +1045,7 @@ meta_xwayland_init_dnd (Display *xdisplay)
9451045 MetaWaylandCompositor * compositor = meta_wayland_compositor_get_default ();
9461046 MetaXWaylandManager * manager = & compositor -> xwayland_manager ;
9471047 MetaXWaylandDnd * dnd = manager -> dnd ;
948- XSetWindowAttributes attributes ;
949- guint32 i , version = XDND_VERSION ;
1048+ guint32 i ;
9501049
9511050 g_assert (manager -> dnd == NULL );
9521051
@@ -955,22 +1054,7 @@ meta_xwayland_init_dnd (Display *xdisplay)
9551054 for (i = 0 ; i < N_DND_ATOMS ; i ++ )
9561055 xdnd_atoms [i ] = gdk_x11_get_xatom_by_name (atom_names [i ]);
9571056
958- attributes .event_mask = PropertyChangeMask | SubstructureNotifyMask ;
959- attributes .override_redirect = True ;
960-
961- dnd -> dnd_window = XCreateWindow (xdisplay ,
962- gdk_x11_window_get_xid (gdk_get_default_root_window ()),
963- -1 , -1 , 1 , 1 ,
964- 0 , /* border width */
965- 0 , /* depth */
966- InputOnly , /* class */
967- CopyFromParent , /* visual */
968- CWEventMask | CWOverrideRedirect ,
969- & attributes );
970- XChangeProperty (xdisplay , dnd -> dnd_window ,
971- xdnd_atoms [ATOM_DND_AWARE ],
972- XA_ATOM , 32 , PropModeReplace ,
973- (guchar * ) & version , 1 );
1057+ create_dnd_windows (dnd , xdisplay );
9741058}
9751059
9761060void
@@ -982,8 +1066,7 @@ meta_xwayland_shutdown_dnd (Display *xdisplay)
9821066
9831067 g_assert (dnd != NULL );
9841068
985- XDestroyWindow (xdisplay , dnd -> dnd_window );
986- dnd -> dnd_window = None ;
1069+ destroy_dnd_windows (dnd , xdisplay );
9871070
9881071 g_slice_free (MetaXWaylandDnd , dnd );
9891072 manager -> dnd = NULL ;
0 commit comments