diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c | 689 |
1 files changed, 689 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c b/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c new file mode 100644 index 0000000..677de38 --- /dev/null +++ b/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_dnd.c | |||
@@ -0,0 +1,689 @@ | |||
1 | #include "ecore_xcb_private.h" | ||
2 | |||
3 | #ifndef MIN | ||
4 | # define MIN(a, b) (((a) < (b)) ? (a) : (b)) | ||
5 | #endif | ||
6 | |||
7 | /* local structures */ | ||
8 | typedef struct _Version_Cache_Item | ||
9 | { | ||
10 | Ecore_X_Window win; | ||
11 | int ver; | ||
12 | } Version_Cache_Item; | ||
13 | |||
14 | /* local function prototypes */ | ||
15 | static Eina_Bool _ecore_xcb_dnd_converter_copy(char *target __UNUSED__, | ||
16 | void *data, | ||
17 | int size, | ||
18 | void **data_ret, | ||
19 | int *size_ret, | ||
20 | Ecore_X_Atom *tprop __UNUSED__, | ||
21 | int *count __UNUSED__); | ||
22 | |||
23 | /* local variables */ | ||
24 | static int _ecore_xcb_dnd_init_count = 0; | ||
25 | static Ecore_X_DND_Source *_source = NULL; | ||
26 | static Ecore_X_DND_Target *_target = NULL; | ||
27 | static Version_Cache_Item *_version_cache = NULL; | ||
28 | static int _version_cache_num = 0, _version_cache_alloc = 0; | ||
29 | static void (*_posupdatecb)(void *, | ||
30 | Ecore_X_Xdnd_Position *); | ||
31 | static void *_posupdatedata; | ||
32 | |||
33 | /* external variables */ | ||
34 | EAPI int ECORE_X_EVENT_XDND_ENTER = 0; | ||
35 | EAPI int ECORE_X_EVENT_XDND_POSITION = 0; | ||
36 | EAPI int ECORE_X_EVENT_XDND_STATUS = 0; | ||
37 | EAPI int ECORE_X_EVENT_XDND_LEAVE = 0; | ||
38 | EAPI int ECORE_X_EVENT_XDND_DROP = 0; | ||
39 | EAPI int ECORE_X_EVENT_XDND_FINISHED = 0; | ||
40 | |||
41 | void | ||
42 | _ecore_xcb_dnd_init(void) | ||
43 | { | ||
44 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
45 | |||
46 | if (!_ecore_xcb_dnd_init_count) | ||
47 | { | ||
48 | _source = calloc(1, sizeof(Ecore_X_DND_Source)); | ||
49 | if (!_source) return; | ||
50 | _source->version = ECORE_X_DND_VERSION; | ||
51 | _source->win = XCB_NONE; | ||
52 | _source->dest = XCB_NONE; | ||
53 | _source->state = ECORE_X_DND_SOURCE_IDLE; | ||
54 | _source->prev.window = 0; | ||
55 | |||
56 | _target = calloc(1, sizeof(Ecore_X_DND_Target)); | ||
57 | if (!_target) | ||
58 | { | ||
59 | free(_source); | ||
60 | _source = NULL; | ||
61 | return; | ||
62 | } | ||
63 | _target->win = XCB_NONE; | ||
64 | _target->source = XCB_NONE; | ||
65 | _target->state = ECORE_X_DND_TARGET_IDLE; | ||
66 | |||
67 | ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new(); | ||
68 | ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new(); | ||
69 | ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new(); | ||
70 | ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new(); | ||
71 | ECORE_X_EVENT_XDND_DROP = ecore_event_type_new(); | ||
72 | ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new(); | ||
73 | } | ||
74 | _ecore_xcb_dnd_init_count++; | ||
75 | } | ||
76 | |||
77 | void | ||
78 | _ecore_xcb_dnd_shutdown(void) | ||
79 | { | ||
80 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
81 | |||
82 | _ecore_xcb_dnd_init_count--; | ||
83 | if (_ecore_xcb_dnd_init_count > 0) return; | ||
84 | if (_source) free(_source); | ||
85 | _source = NULL; | ||
86 | if (_target) free(_target); | ||
87 | _target = NULL; | ||
88 | _ecore_xcb_dnd_init_count = 0; | ||
89 | } | ||
90 | |||
91 | EAPI void | ||
92 | ecore_x_dnd_send_status(Eina_Bool will_accept, | ||
93 | Eina_Bool suppress, | ||
94 | Ecore_X_Rectangle rect, | ||
95 | Ecore_X_Atom action) | ||
96 | { | ||
97 | xcb_client_message_event_t ev; | ||
98 | |||
99 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
100 | CHECK_XCB_CONN; | ||
101 | |||
102 | if (_target->state == ECORE_X_DND_TARGET_IDLE) return; | ||
103 | |||
104 | memset(&ev, 0, sizeof(xcb_client_message_event_t)); | ||
105 | |||
106 | _target->will_accept = will_accept; | ||
107 | |||
108 | ev.response_type = XCB_CLIENT_MESSAGE; | ||
109 | ev.type = ECORE_X_ATOM_XDND_STATUS; | ||
110 | ev.format = 32; | ||
111 | ev.window = _target->source; | ||
112 | ev.data.data32[0] = _target->win; | ||
113 | ev.data.data32[1] = 0; | ||
114 | if (will_accept) ev.data.data32[1] |= 0x1UL; | ||
115 | if (!suppress) ev.data.data32[1] |= 0x2UL; | ||
116 | |||
117 | ev.data.data32[2] = rect.x; | ||
118 | ev.data.data32[2] <<= 16; | ||
119 | ev.data.data32[2] |= rect.y; | ||
120 | ev.data.data32[3] = rect.width; | ||
121 | ev.data.data32[3] <<= 16; | ||
122 | ev.data.data32[3] |= rect.height; | ||
123 | |||
124 | if (will_accept) | ||
125 | ev.data.data32[4] = action; | ||
126 | else | ||
127 | ev.data.data32[4] = XCB_NONE; | ||
128 | _target->accepted_action = action; | ||
129 | |||
130 | xcb_send_event(_ecore_xcb_conn, 0, _target->source, | ||
131 | XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); | ||
132 | // ecore_x_flush(); | ||
133 | } | ||
134 | |||
135 | EAPI Eina_Bool | ||
136 | ecore_x_dnd_drop(void) | ||
137 | { | ||
138 | xcb_client_message_event_t ev; | ||
139 | Eina_Bool status = EINA_FALSE; | ||
140 | |||
141 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
142 | CHECK_XCB_CONN; | ||
143 | |||
144 | memset(&ev, 0, sizeof(xcb_client_message_event_t)); | ||
145 | |||
146 | if (_source->dest) | ||
147 | { | ||
148 | ev.response_type = XCB_CLIENT_MESSAGE; | ||
149 | ev.format = 32; | ||
150 | ev.window = _source->dest; | ||
151 | |||
152 | if (_source->will_accept) | ||
153 | { | ||
154 | ev.type = ECORE_X_ATOM_XDND_DROP; | ||
155 | ev.data.data32[0] = _source->win; | ||
156 | ev.data.data32[1] = 0; | ||
157 | ev.data.data32[2] = _source->time; | ||
158 | |||
159 | xcb_send_event(_ecore_xcb_conn, 0, _source->dest, | ||
160 | XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); | ||
161 | // ecore_x_flush(); | ||
162 | _source->state = ECORE_X_DND_SOURCE_DROPPED; | ||
163 | status = EINA_TRUE; | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | ev.type = ECORE_X_ATOM_XDND_LEAVE; | ||
168 | ev.data.data32[0] = _source->win; | ||
169 | ev.data.data32[1] = 0; | ||
170 | |||
171 | xcb_send_event(_ecore_xcb_conn, 0, _source->dest, | ||
172 | XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); | ||
173 | // ecore_x_flush(); | ||
174 | _source->state = ECORE_X_DND_SOURCE_IDLE; | ||
175 | } | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | ecore_x_selection_xdnd_clear(); | ||
180 | _source->state = ECORE_X_DND_SOURCE_IDLE; | ||
181 | } | ||
182 | |||
183 | ecore_x_window_ignore_set(_source->win, 0); | ||
184 | _source->prev.window = 0; | ||
185 | |||
186 | return status; | ||
187 | } | ||
188 | |||
189 | EAPI void | ||
190 | ecore_x_dnd_aware_set(Ecore_X_Window win, | ||
191 | Eina_Bool on) | ||
192 | { | ||
193 | Ecore_X_Atom prop_data = ECORE_X_DND_VERSION; | ||
194 | |||
195 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
196 | |||
197 | if (on) | ||
198 | ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE, | ||
199 | ECORE_X_ATOM_ATOM, 32, &prop_data, 1); | ||
200 | else | ||
201 | ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE); | ||
202 | } | ||
203 | |||
204 | EAPI int | ||
205 | ecore_x_dnd_version_get(Ecore_X_Window win) | ||
206 | { | ||
207 | unsigned char *data; | ||
208 | int num = 0; | ||
209 | Version_Cache_Item *t; | ||
210 | |||
211 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
212 | |||
213 | if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) | ||
214 | { | ||
215 | if (_version_cache) | ||
216 | { | ||
217 | int i = 0; | ||
218 | |||
219 | for (i = 0; i < _version_cache_num; i++) | ||
220 | { | ||
221 | if (_version_cache[i].win == win) | ||
222 | return _version_cache[i].ver; | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE, | ||
228 | ECORE_X_ATOM_ATOM, 32, &data, &num)) | ||
229 | { | ||
230 | int version = 0; | ||
231 | |||
232 | version = (int)*data; | ||
233 | free(data); | ||
234 | if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) | ||
235 | { | ||
236 | _version_cache_num++; | ||
237 | if (_version_cache_num > _version_cache_alloc) | ||
238 | _version_cache_alloc += 16; | ||
239 | t = realloc(_version_cache, | ||
240 | _version_cache_alloc * sizeof(Version_Cache_Item)); | ||
241 | if (!t) return 0; | ||
242 | _version_cache = t; | ||
243 | _version_cache[_version_cache_num - 1].win = win; | ||
244 | _version_cache[_version_cache_num - 1].ver = version; | ||
245 | } | ||
246 | return version; | ||
247 | } | ||
248 | |||
249 | if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) | ||
250 | { | ||
251 | _version_cache_num++; | ||
252 | if (_version_cache_num > _version_cache_alloc) | ||
253 | _version_cache_alloc += 16; | ||
254 | t = realloc(_version_cache, | ||
255 | _version_cache_alloc * sizeof(Version_Cache_Item)); | ||
256 | if (!t) return 0; | ||
257 | _version_cache = t; | ||
258 | _version_cache[_version_cache_num - 1].win = win; | ||
259 | _version_cache[_version_cache_num - 1].ver = 0; | ||
260 | } | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | EAPI Eina_Bool | ||
266 | ecore_x_dnd_type_isset(Ecore_X_Window win, | ||
267 | const char *type) | ||
268 | { | ||
269 | int num = 0, i = 0; | ||
270 | Eina_Bool ret = EINA_FALSE; | ||
271 | unsigned char *data; | ||
272 | Ecore_X_Atom *atoms, atom; | ||
273 | |||
274 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
275 | CHECK_XCB_CONN; | ||
276 | |||
277 | if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST, | ||
278 | ECORE_X_ATOM_ATOM, 32, &data, &num)) | ||
279 | return ret; | ||
280 | |||
281 | atom = ecore_x_atom_get(type); | ||
282 | atoms = (Ecore_X_Atom *)data; | ||
283 | for (i = 0; i < num; ++i) | ||
284 | { | ||
285 | if (atom == atoms[i]) | ||
286 | { | ||
287 | ret = EINA_TRUE; | ||
288 | break; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | free(data); | ||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | EAPI void | ||
297 | ecore_x_dnd_type_set(Ecore_X_Window win, | ||
298 | const char *type, | ||
299 | Eina_Bool on) | ||
300 | { | ||
301 | Ecore_X_Atom atom, *oldset = NULL, *newset = NULL; | ||
302 | int i = 0, j = 0, num = 0; | ||
303 | unsigned char *data = NULL, *old_data = NULL; | ||
304 | |||
305 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
306 | CHECK_XCB_CONN; | ||
307 | |||
308 | atom = ecore_x_atom_get(type); | ||
309 | ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST, | ||
310 | ECORE_X_ATOM_ATOM, 32, &old_data, &num); | ||
311 | oldset = (Ecore_X_Atom *)old_data; | ||
312 | if (on) | ||
313 | { | ||
314 | if (ecore_x_dnd_type_isset(win, type)) | ||
315 | { | ||
316 | free(old_data); | ||
317 | return; | ||
318 | } | ||
319 | newset = calloc(num + 1, sizeof(Ecore_X_Atom)); | ||
320 | if (!newset) return; | ||
321 | data = (unsigned char *)newset; | ||
322 | for (i = 0; i < num; i++) | ||
323 | newset[i + 1] = oldset[i]; | ||
324 | newset[0] = atom; | ||
325 | ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, | ||
326 | ECORE_X_ATOM_ATOM, 32, data, num + 1); | ||
327 | } | ||
328 | else | ||
329 | { | ||
330 | if (!ecore_x_dnd_type_isset(win, type)) | ||
331 | { | ||
332 | free(old_data); | ||
333 | return; | ||
334 | } | ||
335 | newset = calloc(num - 1, sizeof(Ecore_X_Atom)); | ||
336 | if (!newset) | ||
337 | { | ||
338 | free(old_data); | ||
339 | return; | ||
340 | } | ||
341 | data = (unsigned char *)newset; | ||
342 | for (i = 0; i < num; i++) | ||
343 | if (oldset[i] != atom) | ||
344 | newset[j++] = oldset[i]; | ||
345 | ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, | ||
346 | ECORE_X_ATOM_ATOM, 32, data, num - 1); | ||
347 | } | ||
348 | free(oldset); | ||
349 | free(newset); | ||
350 | } | ||
351 | |||
352 | EAPI void | ||
353 | ecore_x_dnd_types_set(Ecore_X_Window win, | ||
354 | const char **types, | ||
355 | unsigned int num_types) | ||
356 | { | ||
357 | Ecore_X_Atom *newset = NULL; | ||
358 | unsigned int i; | ||
359 | unsigned char *data = NULL; | ||
360 | |||
361 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
362 | CHECK_XCB_CONN; | ||
363 | |||
364 | if (!num_types) | ||
365 | ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST); | ||
366 | else | ||
367 | { | ||
368 | newset = calloc(num_types, sizeof(Ecore_X_Atom)); | ||
369 | if (!newset) return; | ||
370 | |||
371 | data = (unsigned char *)newset; | ||
372 | for (i = 0; i < num_types; i++) | ||
373 | { | ||
374 | newset[i] = ecore_x_atom_get(types[i]); | ||
375 | ecore_x_selection_converter_atom_add(newset[i], | ||
376 | _ecore_xcb_dnd_converter_copy); | ||
377 | } | ||
378 | ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, | ||
379 | ECORE_X_ATOM_ATOM, 32, data, | ||
380 | num_types); | ||
381 | free(newset); | ||
382 | } | ||
383 | } | ||
384 | |||
385 | EAPI void | ||
386 | ecore_x_dnd_actions_set(Ecore_X_Window win, | ||
387 | Ecore_X_Atom *actions, | ||
388 | unsigned int num_actions) | ||
389 | { | ||
390 | unsigned int i; | ||
391 | unsigned char *data = NULL; | ||
392 | |||
393 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
394 | CHECK_XCB_CONN; | ||
395 | |||
396 | if (!num_actions) | ||
397 | ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST); | ||
398 | else | ||
399 | { | ||
400 | data = (unsigned char *)actions; | ||
401 | for (i = 0; i < num_actions; i++) | ||
402 | ecore_x_selection_converter_atom_add(actions[i], | ||
403 | _ecore_xcb_dnd_converter_copy); | ||
404 | ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST, | ||
405 | ECORE_X_ATOM_ATOM, 32, data, | ||
406 | num_actions); | ||
407 | } | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * The DND position update cb is called Ecore_X sends a DND position to a | ||
412 | * client. | ||
413 | * | ||
414 | * It essentially mirrors some of the data sent in the position message. | ||
415 | * Generally this cb should be set just before position update is called. | ||
416 | * Please note well you need to look after your own data pointer if someone | ||
417 | * trashes you position update cb set. | ||
418 | * | ||
419 | * It is considered good form to clear this when the dnd event finishes. | ||
420 | * | ||
421 | * @param cb Callback to updated each time ecore_x sends a position update. | ||
422 | * @param data User data. | ||
423 | */ | ||
424 | EAPI void | ||
425 | ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, | ||
426 | Ecore_X_Xdnd_Position *data), | ||
427 | const void *data) | ||
428 | { | ||
429 | _posupdatecb = cb; | ||
430 | _posupdatedata = (void *)data; | ||
431 | } | ||
432 | |||
433 | EAPI Eina_Bool | ||
434 | ecore_x_dnd_begin(Ecore_X_Window source, | ||
435 | unsigned char *data, | ||
436 | int size) | ||
437 | { | ||
438 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
439 | |||
440 | if (!ecore_x_dnd_version_get(source)) return EINA_FALSE; | ||
441 | |||
442 | /* Take ownership of XdndSelection */ | ||
443 | if (!ecore_x_selection_xdnd_set(source, data, size)) return EINA_FALSE; | ||
444 | |||
445 | if (_version_cache) | ||
446 | { | ||
447 | free(_version_cache); | ||
448 | _version_cache = NULL; | ||
449 | _version_cache_num = 0; | ||
450 | _version_cache_alloc = 0; | ||
451 | } | ||
452 | |||
453 | ecore_x_window_shadow_tree_flush(); | ||
454 | |||
455 | _source->win = source; | ||
456 | ecore_x_window_ignore_set(_source->win, 1); | ||
457 | _source->state = ECORE_X_DND_SOURCE_DRAGGING; | ||
458 | _source->time = _ecore_xcb_events_last_time_get(); | ||
459 | _source->prev.window = 0; | ||
460 | |||
461 | /* Default Accepted Action: move */ | ||
462 | _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE; | ||
463 | _source->accepted_action = XCB_NONE; | ||
464 | _source->dest = XCB_NONE; | ||
465 | |||
466 | return EINA_TRUE; | ||
467 | } | ||
468 | |||
469 | EAPI void | ||
470 | ecore_x_dnd_send_finished(void) | ||
471 | { | ||
472 | xcb_client_message_event_t ev; | ||
473 | |||
474 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
475 | CHECK_XCB_CONN; | ||
476 | |||
477 | if (_target->state == ECORE_X_DND_TARGET_IDLE) return; | ||
478 | |||
479 | memset(&ev, 0, sizeof(xcb_client_message_event_t)); | ||
480 | |||
481 | ev.response_type = XCB_CLIENT_MESSAGE; | ||
482 | ev.format = 32; | ||
483 | ev.type = ECORE_X_ATOM_XDND_FINISHED; | ||
484 | ev.window = _target->source; | ||
485 | ev.data.data32[0] = _target->win; | ||
486 | ev.data.data32[1] = 0; | ||
487 | ev.data.data32[2] = 0; | ||
488 | if (_target->will_accept) | ||
489 | { | ||
490 | ev.data.data32[1] |= 0x1UL; | ||
491 | ev.data.data32[2] = _target->accepted_action; | ||
492 | } | ||
493 | |||
494 | xcb_send_event(_ecore_xcb_conn, 0, _target->source, | ||
495 | XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); | ||
496 | // ecore_x_flush(); | ||
497 | _target->state = ECORE_X_DND_TARGET_IDLE; | ||
498 | } | ||
499 | |||
500 | EAPI void | ||
501 | ecore_x_dnd_source_action_set(Ecore_X_Atom action) | ||
502 | { | ||
503 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
504 | |||
505 | _source->action = action; | ||
506 | if (_source->prev.window) | ||
507 | _ecore_xcb_dnd_drag(_source->prev.window, | ||
508 | _source->prev.x, _source->prev.y); | ||
509 | } | ||
510 | |||
511 | Ecore_X_DND_Source * | ||
512 | _ecore_xcb_dnd_source_get(void) | ||
513 | { | ||
514 | return _source; | ||
515 | } | ||
516 | |||
517 | Ecore_X_DND_Target * | ||
518 | _ecore_xcb_dnd_target_get(void) | ||
519 | { | ||
520 | return _target; | ||
521 | } | ||
522 | |||
523 | void | ||
524 | _ecore_xcb_dnd_drag(Ecore_X_Window root, | ||
525 | int x, | ||
526 | int y) | ||
527 | { | ||
528 | xcb_client_message_event_t ev; | ||
529 | Ecore_X_Window win, *skip; | ||
530 | Ecore_X_Xdnd_Position pos; | ||
531 | int num = 0; | ||
532 | |||
533 | if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) return; | ||
534 | |||
535 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
536 | CHECK_XCB_CONN; | ||
537 | |||
538 | memset(&ev, 0, sizeof(xcb_client_message_event_t)); | ||
539 | |||
540 | ev.response_type = XCB_CLIENT_MESSAGE; | ||
541 | ev.format = 32; | ||
542 | |||
543 | skip = ecore_x_window_ignore_list(&num); | ||
544 | win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num); | ||
545 | while ((win) && !(ecore_x_dnd_version_get(win))) | ||
546 | win = ecore_x_window_shadow_parent_get(root, win); | ||
547 | |||
548 | if ((_source->dest) && (win != _source->dest)) | ||
549 | { | ||
550 | ev.window = _source->dest; | ||
551 | ev.type = ECORE_X_ATOM_XDND_LEAVE; | ||
552 | ev.data.data32[0] = _source->win; | ||
553 | ev.data.data32[1] = 0; | ||
554 | |||
555 | xcb_send_event(_ecore_xcb_conn, 0, _source->dest, | ||
556 | XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); | ||
557 | // ecore_x_flush(); | ||
558 | _source->suppress = 0; | ||
559 | } | ||
560 | |||
561 | if (win) | ||
562 | { | ||
563 | int x1, x2, y1, y2; | ||
564 | |||
565 | _source->version = MIN(ECORE_X_DND_VERSION, | ||
566 | ecore_x_dnd_version_get(win)); | ||
567 | if (win != _source->dest) | ||
568 | { | ||
569 | int i = 0; | ||
570 | unsigned char *data; | ||
571 | Ecore_X_Atom *types; | ||
572 | |||
573 | ecore_x_window_prop_property_get(_source->win, | ||
574 | ECORE_X_ATOM_XDND_TYPE_LIST, | ||
575 | ECORE_X_ATOM_ATOM, 32, | ||
576 | &data, &num); | ||
577 | types = (Ecore_X_Atom *)data; | ||
578 | ev.window = win; | ||
579 | ev.type = ECORE_X_ATOM_XDND_ENTER; | ||
580 | ev.data.data32[0] = _source->win; | ||
581 | ev.data.data32[1] = 0; | ||
582 | if (num > 3) | ||
583 | ev.data.data32[1] |= 0x1UL; | ||
584 | else | ||
585 | ev.data.data32[1] &= 0xfffffffeUL; | ||
586 | ev.data.data32[1] |= ((unsigned long)_source->version) << 24; | ||
587 | |||
588 | for (i = 2; i < 5; i++) | ||
589 | ev.data.data32[i] = 0; | ||
590 | for (i = 0; i < MIN(num, 3); ++i) | ||
591 | ev.data.data32[i + 2] = types[i]; | ||
592 | free(data); | ||
593 | |||
594 | xcb_send_event(_ecore_xcb_conn, 0, win, | ||
595 | XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); | ||
596 | // ecore_x_flush(); | ||
597 | _source->await_status = 0; | ||
598 | _source->will_accept = 0; | ||
599 | } | ||
600 | |||
601 | x1 = _source->rectangle.x; | ||
602 | x2 = _source->rectangle.x + _source->rectangle.width; | ||
603 | y1 = _source->rectangle.y; | ||
604 | y2 = _source->rectangle.y + _source->rectangle.height; | ||
605 | |||
606 | if ((!_source->await_status) || (!_source->suppress) || | ||
607 | ((x < x1) || (x > x2) || (y < y1) || (y > y2))) | ||
608 | { | ||
609 | ev.window = win; | ||
610 | ev.type = ECORE_X_ATOM_XDND_POSITION; | ||
611 | ev.data.data32[0] = _source->win; | ||
612 | ev.data.data32[1] = 0; | ||
613 | ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff); | ||
614 | ev.data.data32[3] = _source->time; | ||
615 | ev.data.data32[4] = _source->action; | ||
616 | |||
617 | xcb_send_event(_ecore_xcb_conn, 0, win, | ||
618 | XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); | ||
619 | // ecore_x_flush(); | ||
620 | _source->await_status = 1; | ||
621 | } | ||
622 | } | ||
623 | |||
624 | if (_posupdatecb) | ||
625 | { | ||
626 | pos.position.x = x; | ||
627 | pos.position.y = y; | ||
628 | pos.win = win; | ||
629 | pos.prev = _source->dest; | ||
630 | _posupdatecb(_posupdatedata, &pos); | ||
631 | } | ||
632 | |||
633 | _source->prev.x = x; | ||
634 | _source->prev.y = y; | ||
635 | _source->prev.window = root; | ||
636 | _source->dest = win; | ||
637 | } | ||
638 | |||
639 | EAPI Ecore_X_Atom | ||
640 | ecore_x_dnd_source_action_get(void) | ||
641 | { | ||
642 | return _source->action; | ||
643 | } | ||
644 | |||
645 | /* local functions */ | ||
646 | static Eina_Bool | ||
647 | _ecore_xcb_dnd_converter_copy(char *target __UNUSED__, | ||
648 | void *data, | ||
649 | int size, | ||
650 | void **data_ret, | ||
651 | int *size_ret, | ||
652 | Ecore_X_Atom *tprop __UNUSED__, | ||
653 | int *count __UNUSED__) | ||
654 | { | ||
655 | Ecore_Xcb_Textproperty text_prop; | ||
656 | Ecore_Xcb_Encoding_Style style = XcbTextStyle; | ||
657 | char *mystr; | ||
658 | |||
659 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
660 | |||
661 | if ((!data) || (!size)) return EINA_FALSE; | ||
662 | |||
663 | mystr = calloc(1, size + 1); | ||
664 | if (!mystr) return EINA_FALSE; | ||
665 | |||
666 | memcpy(mystr, data, size); | ||
667 | if (_ecore_xcb_mb_textlist_to_textproperty(&mystr, 1, style, &text_prop)) | ||
668 | { | ||
669 | int len; | ||
670 | |||
671 | len = strlen((char *)text_prop.value) + 1; | ||
672 | if (!(*data_ret = malloc(len))) | ||
673 | { | ||
674 | free(mystr); | ||
675 | return EINA_FALSE; | ||
676 | } | ||
677 | memcpy(*data_ret, text_prop.value, len); | ||
678 | *size_ret = len; | ||
679 | free(text_prop.value); | ||
680 | free(mystr); | ||
681 | return EINA_TRUE; | ||
682 | } | ||
683 | else | ||
684 | { | ||
685 | free(mystr); | ||
686 | return EINA_FALSE; | ||
687 | } | ||
688 | } | ||
689 | |||