@@ -163,76 +163,207 @@ static void xwm_dnd_send_leave(struct wlr_xwm *xwm) {
163
163
xwm_dnd_send_event(xwm, xwm->atoms[DND_FINISHED], &data);
164
164
}*/
165
165
166
- int xwm_handle_selection_client_message (struct wlr_xwm * xwm ,
167
- xcb_client_message_event_t * ev ) {
168
- if (ev -> type == xwm -> atoms [DND_STATUS ]) {
169
- if (xwm -> drag == NULL ) {
170
- wlr_log (L_DEBUG , "ignoring XdndStatus client message because "
171
- "there's no drag" );
172
- return 1 ;
173
- }
166
+ /**
167
+ * Handle a status message for an outgoing DnD operation.
168
+ */
169
+ static void xwm_handle_dnd_status (struct wlr_xwm * xwm ,
170
+ xcb_client_message_data_t * data ) {
171
+ if (xwm -> drag == NULL ) {
172
+ wlr_log (L_DEBUG , "ignoring XdndStatus client message because "
173
+ "there's no drag" );
174
+ return ;
175
+ }
174
176
175
- xcb_client_message_data_t * data = & ev -> data ;
176
- xcb_window_t target_window = data -> data32 [0 ];
177
- bool accepted = data -> data32 [1 ] & 1 ;
178
- xcb_atom_t action_atom = data -> data32 [4 ];
177
+ xcb_window_t target_window = data -> data32 [0 ];
178
+ bool accepted = data -> data32 [1 ] & 1 ;
179
+ xcb_atom_t action_atom = data -> data32 [4 ];
179
180
180
- if (xwm -> drag_focus == NULL ||
181
- target_window != xwm -> drag_focus -> window_id ) {
182
- wlr_log (L_DEBUG , "ignoring XdndStatus client message because "
183
- "it doesn't match the current drag focus window ID" );
184
- return 1 ;
185
- }
181
+ if (xwm -> drag_focus == NULL ||
182
+ target_window != xwm -> drag_focus -> window_id ) {
183
+ wlr_log (L_DEBUG , "ignoring XdndStatus client message because "
184
+ "it doesn't match the current drag focus window ID" );
185
+ return ;
186
+ }
186
187
187
- enum wl_data_device_manager_dnd_action action =
188
- data_device_manager_dnd_action_from_atom (xwm , action_atom );
188
+ enum wl_data_device_manager_dnd_action action =
189
+ data_device_manager_dnd_action_from_atom (xwm , action_atom );
189
190
190
- struct wlr_drag * drag = xwm -> drag ;
191
- assert (drag != NULL );
191
+ struct wlr_drag * drag = xwm -> drag ;
192
+ assert (drag != NULL );
192
193
193
- drag -> source -> accepted = accepted ;
194
- wlr_data_source_dnd_action (drag -> source , action );
194
+ drag -> source -> accepted = accepted ;
195
+ wlr_data_source_dnd_action (drag -> source , action );
195
196
196
- wlr_log (L_DEBUG , "DND_STATUS window=%d accepted=%d action=%d" ,
197
- target_window , accepted , action );
198
- return 1 ;
199
- } else if (ev -> type == xwm -> atoms [DND_FINISHED ]) {
200
- // This should only happen after the drag has ended, but before the drag
201
- // source is destroyed
202
- if (xwm -> seat == NULL || xwm -> seat -> drag_source == NULL ||
203
- xwm -> drag != NULL ) {
204
- wlr_log (L_DEBUG , "ignoring XdndFinished client message because "
205
- "there's no finished drag" );
206
- return 1 ;
207
- }
197
+ wlr_log (L_DEBUG , "DND_STATUS window=%d accepted=%d action=%d" ,
198
+ target_window , accepted , action );
199
+ }
208
200
209
- struct wlr_data_source * source = xwm -> seat -> drag_source ;
201
+ /**
202
+ * Handle a finish message for an outgoing DnD operation.
203
+ */
204
+ static void xwm_handle_dnd_finished (struct wlr_xwm * xwm ,
205
+ xcb_client_message_data_t * data ) {
206
+ // This should only happen after the drag has ended, but before the drag
207
+ // source is destroyed
208
+ if (xwm -> seat == NULL || xwm -> seat -> drag_source == NULL ||
209
+ xwm -> drag != NULL ) {
210
+ wlr_log (L_DEBUG , "ignoring XdndFinished client message because "
211
+ "there's no finished drag" );
212
+ return ;
213
+ }
214
+
215
+ struct wlr_data_source * source = xwm -> seat -> drag_source ;
216
+
217
+ xcb_window_t target_window = data -> data32 [0 ];
218
+ bool performed = data -> data32 [1 ] & 1 ;
219
+ xcb_atom_t action_atom = data -> data32 [2 ];
220
+
221
+ if (xwm -> drag_focus == NULL ||
222
+ target_window != xwm -> drag_focus -> window_id ) {
223
+ wlr_log (L_DEBUG , "ignoring XdndFinished client message because "
224
+ "it doesn't match the finished drag focus window ID" );
225
+ return ;
226
+ }
227
+
228
+ enum wl_data_device_manager_dnd_action action =
229
+ data_device_manager_dnd_action_from_atom (xwm , action_atom );
230
+
231
+ if (performed ) {
232
+ wlr_data_source_dnd_finish (source );
233
+ }
210
234
211
- xcb_client_message_data_t * data = & ev -> data ;
212
- xcb_window_t target_window = data -> data32 [0 ];
213
- bool performed = data -> data32 [1 ] & 1 ;
214
- xcb_atom_t action_atom = data -> data32 [2 ];
235
+ wlr_log (L_DEBUG , "DND_FINISH window=%d performed=%d action=%d" ,
236
+ target_window , performed , action );
237
+ }
238
+
239
+ static bool xwm_add_atom_to_mime_types (struct wlr_xwm * xwm ,
240
+ struct wl_array * mime_types , xcb_atom_t atom ) {
241
+ char * mime_type = xwm_mime_type_from_atom (xwm , atom );
242
+ if (mime_type == NULL ) {
243
+ return false;
244
+ }
245
+ char * * mime_type_ptr =
246
+ wl_array_add (mime_types , sizeof (* mime_type_ptr ));
247
+ if (mime_type_ptr == NULL ) {
248
+ return false;
249
+ }
250
+ * mime_type_ptr = mime_type ;
251
+ return true;
252
+ }
253
+
254
+ static bool xwm_dnd_get_mime_types (struct wlr_xwm * xwm ,
255
+ struct wl_array * mime_types , xcb_window_t source ) {
256
+ xcb_get_property_cookie_t cookie = xcb_get_property (xwm -> xcb_conn ,
257
+ 1 , // delete
258
+ source ,
259
+ xwm -> atoms [DND_TYPE_LIST ],
260
+ XCB_GET_PROPERTY_TYPE_ANY ,
261
+ 0 , // offset
262
+ 0x1fffffff // length
263
+ );
264
+
265
+ xcb_get_property_reply_t * reply =
266
+ xcb_get_property_reply (xwm -> xcb_conn , cookie , NULL );
267
+ if (reply == NULL ) {
268
+ return false;
269
+ }
270
+ if (reply -> type != XCB_ATOM_ATOM || reply -> value_len == 0 ) {
271
+ wlr_log (L_ERROR , "invalid XdndTypeList property" );
272
+ goto error ;
273
+ }
215
274
216
- if ( xwm -> drag_focus == NULL ||
217
- target_window != xwm -> drag_focus -> window_id ) {
218
- wlr_log ( L_DEBUG , "ignoring XdndFinished client message because "
219
- "it doesn't match the finished drag focus window ID " );
220
- return 1 ;
275
+ xcb_atom_t * atoms = xcb_get_property_value ( reply );
276
+ for ( uint32_t i = 0 ; i < reply -> value_len ; ++ i ) {
277
+ if (! xwm_add_atom_to_mime_types ( xwm , mime_types , atoms [ i ])) {
278
+ wlr_log ( L_ERROR , "failed to add MIME type atom to list " );
279
+ goto error ;
221
280
}
281
+ }
282
+
283
+ free (reply );
284
+ return true;
285
+
286
+ error :
287
+ free (reply );
288
+ return false;
289
+ }
290
+
291
+ /**
292
+ * Handle an enter message for an incoming DnD operation.
293
+ */
294
+ static void xwm_handle_dnd_enter (struct wlr_xwm * xwm ,
295
+ xcb_client_message_data_t * data ) {
296
+ if (xwm -> seat == NULL ) {
297
+ wlr_log (L_DEBUG , "ignoring XdndEnter client message because "
298
+ "there's no Xwayland seat" );
299
+ return ;
300
+ }
301
+
302
+ xcb_window_t source_window = data -> data32 [0 ];
222
303
223
- enum wl_data_device_manager_dnd_action action =
224
- data_device_manager_dnd_action_from_atom (xwm , action_atom );
304
+ if (source_window != xwm -> dnd_selection .owner ) {
305
+ wlr_log (L_DEBUG , "ignoring XdndEnter client message because "
306
+ "the source window hasn't set the drag-and-drop selection" );
307
+ return ;
308
+ }
225
309
226
- if (performed ) {
227
- wlr_data_source_dnd_finish (source );
310
+ struct wl_array mime_types ;
311
+ wl_array_init (& mime_types );
312
+ if ((data -> data32 [1 ] & 1 ) == 0 ) {
313
+ // Less than 3 MIME types, those are in the message data
314
+ for (size_t i = 0 ; i < 3 ; ++ i ) {
315
+ xcb_atom_t atom = data -> data32 [2 + i ];
316
+ if (atom == XCB_ATOM_NONE ) {
317
+ break ;
318
+ }
319
+ if (!xwm_add_atom_to_mime_types (xwm , & mime_types , atom )) {
320
+ wlr_log (L_ERROR , "failed to add MIME type atom to list" );
321
+ break ;
322
+ }
323
+ }
324
+ } else {
325
+ if (!xwm_dnd_get_mime_types (xwm , & mime_types , source_window )) {
326
+ wlr_log (L_ERROR , "failed to add MIME type atom to list" );
228
327
}
328
+ }
229
329
230
- wlr_log (L_DEBUG , "DND_FINISH window=%d performed=%d action=%d" ,
231
- target_window , performed , action );
330
+ wlr_log (L_INFO , "parsed XdndEnter" );
331
+ }
332
+
333
+ int xwm_handle_selection_client_message (struct wlr_xwm * xwm ,
334
+ xcb_client_message_event_t * ev ) {
335
+ // Outgoing
336
+ if (ev -> type == xwm -> atoms [DND_STATUS ]) {
337
+ xwm_handle_dnd_status (xwm , & ev -> data );
232
338
return 1 ;
339
+ } else if (ev -> type == xwm -> atoms [DND_FINISHED ]) {
340
+ xwm_handle_dnd_finished (xwm , & ev -> data );
341
+ return 1 ;
342
+ }
343
+
344
+ // Incoming
345
+ if (ev -> type == xwm -> atoms [DND_ENTER ]) {
346
+ xwm_handle_dnd_enter (xwm , & ev -> data );
347
+ return 1 ;
348
+ }
349
+
350
+ return 0 ;
351
+ }
352
+
353
+ int xwm_dnd_handle_xfixes_selection_notify (struct wlr_xwm * xwm ,
354
+ xcb_xfixes_selection_notify_event_t * event ) {
355
+ assert (event -> selection == xwm -> atoms [DND_SELECTION ]);
356
+ struct wlr_xwm_selection * selection = & xwm -> dnd_selection ;
357
+
358
+ selection -> owner = event -> owner ;
359
+
360
+ if (event -> owner != XCB_ATOM_NONE ) {
361
+ // TODO: start grab
233
362
} else {
234
- return 0 ;
363
+ // TODO: end grab
235
364
}
365
+
366
+ return 1 ;
236
367
}
237
368
238
369
static void seat_handle_drag_focus (struct wl_listener * listener , void * data ) {
0 commit comments