xdnd.c 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600
  1. /* xdnd.c, xdnd.h - C program library for handling the Xdnd protocol
  2. Copyright (C) 1996-2000 Paul Sheer
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  14. 02111-1307, USA.
  15. */
  16. /*
  17. Released 1998-08-07
  18. Changes:
  19. 2000-08-08: INCR protocol implemented.
  20. */
  21. /*
  22. DONE:
  23. - INCR protocol now implemented
  24. TODO:
  25. - action_choose_dialog not yet supported (never called)
  26. - widget_delete_selection not yet supported and DELETE requests are ignored
  27. - not yet tested with applications that only supported XDND 0 or 1
  28. */
  29. #include <X11/Xlib.h>
  30. #include <X11/X.h>
  31. #include <X11/Xatom.h>
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include <stdio.h>
  35. #if TIME_WITH_SYS_TIME
  36. # include <sys/time.h>
  37. # include <time.h>
  38. #else
  39. # if HAVE_SYS_TIME_H
  40. # include <sys/time.h>
  41. # else
  42. # include <time.h>
  43. # endif
  44. #endif
  45. #include <sys/types.h>
  46. #ifdef HAVE_UNISTD_H
  47. # include <unistd.h>
  48. #endif
  49. #ifdef HAVE_SYS_SELECT_H
  50. # include <sys/select.h>
  51. #endif
  52. #include "xdnd.h"
  53. static void xdnd_send_enter (DndClass * dnd, Window window, Window from, Atom * typelist);
  54. static void xdnd_send_position (DndClass * dnd, Window window, Window from, Atom action, int x, int y,
  55. unsigned long etime);
  56. static void xdnd_send_status (DndClass * dnd, Window window, Window from, int will_accept, int want_position,
  57. int x, int y, int w, int h, Atom action);
  58. static void xdnd_send_leave (DndClass * dnd, Window window, Window from);
  59. static void xdnd_send_drop (DndClass * dnd, Window window, Window from, unsigned long etime);
  60. static void xdnd_send_finished (DndClass * dnd, Window window, Window from, int error);
  61. static int xdnd_convert_selection (DndClass * dnd, Window window, Window requester, Atom type);
  62. static void xdnd_selection_send (DndClass * dnd, XSelectionRequestEvent * request, unsigned char *data,
  63. int length);
  64. static int xdnd_get_selection (DndClass * dnd, Window from, Atom property, Window insert);
  65. /* just to remind us : */
  66. #if 0
  67. typedef struct {
  68. int type;
  69. unsigned long serial;
  70. Bool send_event;
  71. Display *display;
  72. Window window;
  73. Atom message_type;
  74. int format;
  75. union {
  76. char b[20];
  77. short s[10];
  78. long l[5];
  79. } data;
  80. } XClientMessageEvent;
  81. XClientMessageEvent xclient;
  82. #endif
  83. /* #define DND_DEBUG */
  84. #define xdnd_xfree(x) {if (x) { free (x); x = 0; }}
  85. #ifdef DND_DEBUG
  86. #include <sys/time.h>
  87. #include <unistd.h>
  88. char *xdnd_debug_milliseconds (void)
  89. {
  90. struct timeval tv;
  91. static char r[22];
  92. gettimeofday (&tv, 0);
  93. sprintf (r, "%.2ld.%.3ld", tv.tv_sec % 100L, tv.tv_usec / 1000L);
  94. return r;
  95. }
  96. #define dnd_debug1(a) printf("%s: %d: %s: " a "\n", __FILE__, __LINE__, xdnd_debug_milliseconds ())
  97. #define dnd_debug2(a,b) printf("%s: %d: %s: " a "\n", __FILE__, __LINE__, xdnd_debug_milliseconds (), b)
  98. #define dnd_debug3(a,b,c) printf("%s: %d: %s: " a "\n", __FILE__, __LINE__, xdnd_debug_milliseconds (), b, c)
  99. #define dnd_debug4(a,b,c,d) printf("%s: %d: %s: " a "\n", __FILE__, __LINE__, xdnd_debug_milliseconds (), b, c, d)
  100. #else
  101. #define dnd_debug1(a)
  102. #define dnd_debug2(a,b)
  103. #define dnd_debug3(a,b,c)
  104. #define dnd_debug4(a,b,c,d)
  105. #endif
  106. #define dnd_warning(a) fprintf (stderr, a)
  107. #define dnd_version_at_least(a,b) ((a) >= (b))
  108. static unsigned char dnd_copy_cursor_bits[] =
  109. {
  110. 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x02, 0x00, 0x08, 0x01,
  111. 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0xe8, 0x0f,
  112. 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x01,
  113. 0x02, 0x00, 0x08, 0x00, 0x02, 0x04, 0x08, 0x00, 0x02, 0x0c, 0x08, 0x00,
  114. 0x02, 0x1c, 0x08, 0x00, 0x02, 0x3c, 0x08, 0x00, 0x02, 0x7c, 0x08, 0x00,
  115. 0x02, 0xfc, 0x08, 0x00, 0x02, 0xfc, 0x09, 0x00, 0x02, 0xfc, 0x0b, 0x00,
  116. 0x02, 0x7c, 0x08, 0x00, 0xfe, 0x6d, 0x0f, 0x00, 0x00, 0xc4, 0x00, 0x00,
  117. 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
  118. 0x00, 0x00, 0x00, 0x00};
  119. static unsigned char dnd_copy_mask_bits[] =
  120. {
  121. 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1f,
  122. 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  123. 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  124. 0x07, 0x06, 0xfc, 0x1f, 0x07, 0x0e, 0xfc, 0x1f, 0x07, 0x1e, 0x1c, 0x00,
  125. 0x07, 0x3e, 0x1c, 0x00, 0x07, 0x7e, 0x1c, 0x00, 0x07, 0xfe, 0x1c, 0x00,
  126. 0x07, 0xfe, 0x1d, 0x00, 0x07, 0xfe, 0x1f, 0x00, 0x07, 0xfe, 0x1f, 0x00,
  127. 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x1e, 0x00, 0xff, 0xef, 0x1f, 0x00,
  128. 0x00, 0xe6, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
  129. 0x00, 0x80, 0x01, 0x00};
  130. static unsigned char dnd_move_cursor_bits[] =
  131. {
  132. 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08,
  133. 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08,
  134. 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x04, 0x08, 0x02, 0x0c, 0x08,
  135. 0x02, 0x1c, 0x08, 0x02, 0x3c, 0x08, 0x02, 0x7c, 0x08, 0x02, 0xfc, 0x08,
  136. 0x02, 0xfc, 0x09, 0x02, 0xfc, 0x0b, 0x02, 0x7c, 0x08, 0xfe, 0x6d, 0x0f,
  137. 0x00, 0xc4, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01,
  138. 0x00, 0x00, 0x00};
  139. static unsigned char dnd_move_mask_bits[] =
  140. {
  141. 0xff, 0xff, 0x1f, 0xff, 0xff, 0x1f, 0xff, 0xff, 0x1f, 0x07, 0x00, 0x1c,
  142. 0x07, 0x00, 0x1c, 0x07, 0x00, 0x1c, 0x07, 0x00, 0x1c, 0x07, 0x00, 0x1c,
  143. 0x07, 0x00, 0x1c, 0x07, 0x06, 0x1c, 0x07, 0x0e, 0x1c, 0x07, 0x1e, 0x1c,
  144. 0x07, 0x3e, 0x1c, 0x07, 0x7e, 0x1c, 0x07, 0xfe, 0x1c, 0x07, 0xfe, 0x1d,
  145. 0x07, 0xfe, 0x1f, 0x07, 0xfe, 0x1f, 0xff, 0xff, 0x1f, 0xff, 0xff, 0x1e,
  146. 0xff, 0xef, 0x1f, 0x00, 0xe6, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03,
  147. 0x00, 0x80, 0x01};
  148. static unsigned char dnd_link_cursor_bits[] =
  149. {
  150. 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x02, 0x00, 0x08, 0x01,
  151. 0x02, 0x00, 0x88, 0x00, 0x02, 0x00, 0x48, 0x00, 0x02, 0x00, 0xe8, 0x0f,
  152. 0x02, 0x00, 0x48, 0x00, 0x02, 0x00, 0x88, 0x00, 0x02, 0x00, 0x08, 0x01,
  153. 0x02, 0x00, 0x08, 0x00, 0x02, 0x04, 0x08, 0x00, 0x02, 0x0c, 0x08, 0x00,
  154. 0x02, 0x1c, 0x08, 0x00, 0x02, 0x3c, 0x08, 0x00, 0x02, 0x7c, 0x08, 0x00,
  155. 0x02, 0xfc, 0x08, 0x00, 0x02, 0xfc, 0x09, 0x00, 0x02, 0xfc, 0x0b, 0x00,
  156. 0x02, 0x7c, 0x08, 0x00, 0xfe, 0x6d, 0x0f, 0x00, 0x00, 0xc4, 0x00, 0x00,
  157. 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
  158. 0x00, 0x00, 0x00, 0x00};
  159. static unsigned char dnd_link_mask_bits[] =
  160. {
  161. 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1f,
  162. 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  163. 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  164. 0x07, 0x06, 0xfc, 0x1f, 0x07, 0x0e, 0xfc, 0x1f, 0x07, 0x1e, 0x1c, 0x00,
  165. 0x07, 0x3e, 0x1c, 0x00, 0x07, 0x7e, 0x1c, 0x00, 0x07, 0xfe, 0x1c, 0x00,
  166. 0x07, 0xfe, 0x1d, 0x00, 0x07, 0xfe, 0x1f, 0x00, 0x07, 0xfe, 0x1f, 0x00,
  167. 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x1e, 0x00, 0xff, 0xef, 0x1f, 0x00,
  168. 0x00, 0xe6, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
  169. 0x00, 0x80, 0x01, 0x00};
  170. static unsigned char dnd_ask_cursor_bits[] =
  171. {
  172. 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x02, 0x00, 0x88, 0x03,
  173. 0x02, 0x00, 0x48, 0x04, 0x02, 0x00, 0x08, 0x04, 0x02, 0x00, 0x08, 0x02,
  174. 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x01, 0x02, 0x00, 0x08, 0x00,
  175. 0x02, 0x00, 0x08, 0x01, 0x02, 0x04, 0x08, 0x00, 0x02, 0x0c, 0x08, 0x00,
  176. 0x02, 0x1c, 0x08, 0x00, 0x02, 0x3c, 0x08, 0x00, 0x02, 0x7c, 0x08, 0x00,
  177. 0x02, 0xfc, 0x08, 0x00, 0x02, 0xfc, 0x09, 0x00, 0x02, 0xfc, 0x0b, 0x00,
  178. 0x02, 0x7c, 0x08, 0x00, 0xfe, 0x6d, 0x0f, 0x00, 0x00, 0xc4, 0x00, 0x00,
  179. 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
  180. 0x00, 0x00, 0x00, 0x00};
  181. static unsigned char dnd_ask_mask_bits[] =
  182. {
  183. 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1f,
  184. 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  185. 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f, 0x07, 0x00, 0xfc, 0x1f,
  186. 0x07, 0x06, 0xfc, 0x1f, 0x07, 0x0e, 0xfc, 0x1f, 0x07, 0x1e, 0x1c, 0x00,
  187. 0x07, 0x3e, 0x1c, 0x00, 0x07, 0x7e, 0x1c, 0x00, 0x07, 0xfe, 0x1c, 0x00,
  188. 0x07, 0xfe, 0x1d, 0x00, 0x07, 0xfe, 0x1f, 0x00, 0x07, 0xfe, 0x1f, 0x00,
  189. 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x1e, 0x00, 0xff, 0xef, 0x1f, 0x00,
  190. 0x00, 0xe6, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
  191. 0x00, 0x80, 0x01, 0x00};
  192. static DndCursor dnd_cursors[] =
  193. {
  194. {29, 25, 10, 10, dnd_copy_cursor_bits, dnd_copy_mask_bits, "XdndActionCopy", 0, 0, 0, 0},
  195. {21, 25, 10, 10, dnd_move_cursor_bits, dnd_move_mask_bits, "XdndActionMove", 0, 0, 0, 0},
  196. {29, 25, 10, 10, dnd_link_cursor_bits, dnd_link_mask_bits, "XdndActionLink", 0, 0, 0, 0},
  197. {29, 25, 10, 10, dnd_ask_cursor_bits, dnd_ask_mask_bits, "XdndActionAsk", 0, 0, 0, 0},
  198. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  199. };
  200. void xdnd_reset (DndClass * dnd)
  201. {
  202. dnd->stage = XDND_DROP_STAGE_IDLE;
  203. dnd->dragging_version = 0;
  204. dnd->internal_drag = 0;
  205. dnd->want_position = 0;
  206. dnd->ready_to_drop = 0;
  207. dnd->will_accept = 0;
  208. dnd->rectangle.x = dnd->rectangle.y = 0;
  209. dnd->rectangle.width = dnd->rectangle.height = 0;
  210. dnd->dropper_window = 0;
  211. dnd->dropper_toplevel = 0;
  212. dnd->dragger_window = 0;
  213. dnd->dragger_typelist = 0;
  214. dnd->desired_type = 0;
  215. dnd->time = 0;
  216. }
  217. void xdnd_init (DndClass * dnd, Display * display)
  218. {
  219. DndCursor *cursor;
  220. XColor black, white;
  221. memset (dnd, 0, sizeof (*dnd));
  222. dnd->display = display;
  223. dnd->root_window = DefaultRootWindow (display);
  224. dnd->version = XDND_VERSION;
  225. dnd->XdndAware = XInternAtom (dnd->display, "XdndAware", False);
  226. dnd->XdndSelection = XInternAtom (dnd->display, "XdndSelection", False);
  227. dnd->XdndEnter = XInternAtom (dnd->display, "XdndEnter", False);
  228. dnd->XdndLeave = XInternAtom (dnd->display, "XdndLeave", False);
  229. dnd->XdndPosition = XInternAtom (dnd->display, "XdndPosition", False);
  230. dnd->XdndDrop = XInternAtom (dnd->display, "XdndDrop", False);
  231. dnd->XdndFinished = XInternAtom (dnd->display, "XdndFinished", False);
  232. dnd->XdndStatus = XInternAtom (dnd->display, "XdndStatus", False);
  233. dnd->XdndActionCopy = XInternAtom (dnd->display, "XdndActionCopy", False);
  234. dnd->XdndActionMove = XInternAtom (dnd->display, "XdndActionMove", False);
  235. dnd->XdndActionLink = XInternAtom (dnd->display, "XdndActionLink", False);
  236. dnd->XdndActionAsk = XInternAtom (dnd->display, "XdndActionAsk", False);
  237. dnd->XdndActionPrivate = XInternAtom (dnd->display, "XdndActionPrivate", False);
  238. dnd->XdndTypeList = XInternAtom (dnd->display, "XdndTypeList", False);
  239. dnd->XdndActionList = XInternAtom (dnd->display, "XdndActionList", False);
  240. dnd->XdndActionDescription = XInternAtom (dnd->display, "XdndActionDescription", False);
  241. dnd->Xdnd_NON_PROTOCOL_ATOM = XInternAtom (dnd->display, "JXSelectionWindowProperty", False);
  242. xdnd_reset (dnd);
  243. dnd->cursors = dnd_cursors;
  244. black.pixel = BlackPixel (dnd->display, DefaultScreen (dnd->display));
  245. white.pixel = WhitePixel (dnd->display, DefaultScreen (dnd->display));
  246. XQueryColor (dnd->display, DefaultColormap (dnd->display, DefaultScreen (dnd->display)), &black);
  247. XQueryColor (dnd->display, DefaultColormap (dnd->display, DefaultScreen (dnd->display)), &white);
  248. for (cursor = &dnd->cursors[0]; cursor->width; cursor++) {
  249. cursor->image_pixmap = XCreateBitmapFromData \
  250. (dnd->display, dnd->root_window, (char *) cursor->image_data, cursor->width, cursor->height);
  251. cursor->mask_pixmap = XCreateBitmapFromData \
  252. (dnd->display, dnd->root_window, (char *) cursor->mask_data, cursor->width, cursor->height);
  253. cursor->cursor = XCreatePixmapCursor (dnd->display, cursor->image_pixmap,
  254. cursor->mask_pixmap, &black, &white, cursor->x, cursor->y);
  255. XFreePixmap (dnd->display, cursor->image_pixmap);
  256. XFreePixmap (dnd->display, cursor->mask_pixmap);
  257. cursor->action = XInternAtom (dnd->display, cursor->_action, False);
  258. }
  259. }
  260. void xdnd_shut (DndClass * dnd)
  261. {
  262. DndCursor *cursor;
  263. for (cursor = &dnd->cursors[0]; cursor->width; cursor++)
  264. XFreeCursor (dnd->display, cursor->cursor);
  265. memset (dnd, 0, sizeof (*dnd));
  266. return;
  267. }
  268. /* typelist is a null terminated array */
  269. static int array_length (Atom * a)
  270. {
  271. int n;
  272. for (n = 0; a[n]; n++);
  273. return n;
  274. }
  275. void xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist)
  276. {
  277. Window root_return, parent;
  278. unsigned int nchildren_return;
  279. Window *children_return = 0;
  280. int r, s;
  281. if(!window) return;
  282. if (dnd->widget_exists)
  283. if (!(*dnd->widget_exists) (dnd, window))
  284. return;
  285. s = XChangeProperty (dnd->display, window, dnd->XdndAware, XA_ATOM, 32, PropModeReplace,
  286. (unsigned char *) &dnd->version, 1);
  287. #if 1
  288. dnd_debug4 ("XChangeProperty() = %d, window = %ld, widget = %s", s, window, "<WIDGET>");
  289. #endif
  290. if (s && typelist) {
  291. int n;
  292. n = array_length (typelist);
  293. if (n)
  294. s = XChangeProperty (dnd->display, window, dnd->XdndAware, XA_ATOM, 32, PropModeAppend,
  295. (unsigned char *) typelist, n);
  296. }
  297. r =
  298. XQueryTree (dnd->display, window, &root_return, &parent, &children_return,
  299. &nchildren_return);
  300. if (children_return)
  301. XFree (children_return);
  302. if (r && parent != root_return)
  303. xdnd_set_dnd_aware (dnd, parent, typelist);
  304. }
  305. int xdnd_is_dnd_aware (DndClass * dnd, Window window, int *version, Atom * typelist)
  306. {
  307. Atom actual;
  308. int format;
  309. unsigned long count, remaining;
  310. unsigned char *data = 0;
  311. Atom *types, *t;
  312. int result = 1;
  313. *version = 0;
  314. XGetWindowProperty (dnd->display, window, dnd->XdndAware,
  315. 0, 0x8000000L, False, XA_ATOM,
  316. &actual, &format,
  317. &count, &remaining, &data);
  318. if (actual != XA_ATOM || format != 32 || count == 0 || !data) {
  319. dnd_debug2 ("XGetWindowProperty failed in xdnd_is_dnd_aware - XdndAware = %ld", dnd->XdndAware);
  320. if (data)
  321. XFree (data);
  322. return 0;
  323. }
  324. types = (Atom *) data;
  325. #if XDND_VERSION >= 3
  326. if (types[0] < 3) {
  327. if (data)
  328. XFree (data);
  329. return 0;
  330. }
  331. #endif
  332. *version = dnd->version < types[0] ? dnd->version : types[0]; /* minimum */
  333. dnd_debug2 ("Using XDND version %d", *version);
  334. if (count > 1) {
  335. result = 0;
  336. for (t = typelist; *t; t++) {
  337. int j;
  338. for (j = 1; j < count; j++) {
  339. if (types[j] == *t) {
  340. result = 1;
  341. break;
  342. }
  343. }
  344. if (result)
  345. break;
  346. }
  347. }
  348. XFree (data);
  349. return result;
  350. }
  351. void xdnd_set_type_list (DndClass * dnd, Window window, Atom * typelist)
  352. {
  353. int n;
  354. n = array_length (typelist);
  355. XChangeProperty (dnd->display, window, dnd->XdndTypeList, XA_ATOM, 32,
  356. PropModeReplace, (unsigned char *) typelist, n);
  357. }
  358. /* result must be free'd */
  359. void xdnd_get_type_list (DndClass * dnd, Window window, Atom ** typelist)
  360. {
  361. Atom type, *a;
  362. int format, i;
  363. unsigned long count, remaining;
  364. unsigned char *data = NULL;
  365. *typelist = 0;
  366. XGetWindowProperty (dnd->display, window, dnd->XdndTypeList,
  367. 0, 0x8000000L, False, XA_ATOM,
  368. &type, &format, &count, &remaining, &data);
  369. if (type != XA_ATOM || format != 32 || count == 0 || !data) {
  370. if (data)
  371. XFree (data);
  372. dnd_debug2 ("XGetWindowProperty failed in xdnd_get_type_list - dnd->XdndTypeList = %ld", dnd->XdndTypeList);
  373. return;
  374. }
  375. *typelist = malloc ((count + 1) * sizeof (Atom));
  376. a = (Atom *) data;
  377. for (i = 0; i < count; i++)
  378. (*typelist)[i] = a[i];
  379. (*typelist)[count] = 0;
  380. XFree (data);
  381. }
  382. void xdnd_get_three_types (DndClass * dnd, XEvent * xevent, Atom ** typelist)
  383. {
  384. int i;
  385. *typelist = malloc ((XDND_THREE + 1) * sizeof (Atom));
  386. for (i = 0; i < XDND_THREE; i++)
  387. (*typelist)[i] = XDND_ENTER_TYPE (xevent, i);
  388. (*typelist)[XDND_THREE] = 0; /* although (*typelist)[1] or (*typelist)[2] may also be set to nill */
  389. }
  390. /* result must be free'd */
  391. static char *concat_string_list (char **t, int *bytes)
  392. {
  393. int l, n;
  394. char *s;
  395. for (l = n = 0;; n++) {
  396. if (!t[n])
  397. break;
  398. if (!t[n][0])
  399. break;
  400. l += strlen (t[n]) + 1;
  401. }
  402. s = malloc (l + 1);
  403. for (l = n = 0;; n++) {
  404. if (!t[n])
  405. break;
  406. if (!(t[n][0]))
  407. break;
  408. strcpy (s + l, t[n]);
  409. l += strlen (t[n]) + 1;
  410. }
  411. *bytes = l;
  412. s[l] = '\0';
  413. return s;
  414. }
  415. void xdnd_set_actions (DndClass * dnd, Window window, Atom * actions, char **descriptions)
  416. {
  417. int n, l;
  418. char *s;
  419. n = array_length (actions);
  420. XChangeProperty (dnd->display, window, dnd->XdndActionList, XA_ATOM, 32,
  421. PropModeReplace, (unsigned char *) actions, n);
  422. s = concat_string_list (descriptions, &l);
  423. XChangeProperty (dnd->display, window, dnd->XdndActionList, XA_STRING, 8,
  424. PropModeReplace, (unsigned char *) s, l);
  425. xdnd_xfree (s);
  426. }
  427. /* returns 1 on error or no actions, otherwise result must be free'd
  428. xdnd_get_actions (window, &actions, &descriptions);
  429. free (actions); free (descriptions); */
  430. int xdnd_get_actions (DndClass * dnd, Window window, Atom ** actions, char ***descriptions)
  431. {
  432. Atom type, *a;
  433. int format, i;
  434. unsigned long count, dcount, remaining;
  435. unsigned char *data = 0, *r;
  436. *actions = 0;
  437. *descriptions = 0;
  438. XGetWindowProperty (dnd->display, window, dnd->XdndActionList,
  439. 0, 0x8000000L, False, XA_ATOM,
  440. &type, &format, &count, &remaining, &data);
  441. if (type != XA_ATOM || format != 32 || count == 0 || !data) {
  442. if (data)
  443. XFree (data);
  444. return 1;
  445. }
  446. *actions = malloc ((count + 1) * sizeof (Atom));
  447. a = (Atom *) data;
  448. for (i = 0; i < count; i++)
  449. (*actions)[i] = a[i];
  450. (*actions)[count] = 0;
  451. XFree (data);
  452. data = 0;
  453. XGetWindowProperty (dnd->display, window, dnd->XdndActionDescription,
  454. 0, 0x8000000L, False, XA_STRING, &type, &format,
  455. &dcount, &remaining, &data);
  456. if (type != XA_STRING || format != 8 || dcount == 0) {
  457. if (data)
  458. XFree (data);
  459. *descriptions = malloc ((count + 1) * sizeof (char *));
  460. dnd_warning ("XGetWindowProperty no property or wrong format for action descriptions");
  461. for (i = 0; i < count; i++)
  462. (*descriptions)[i] = "";
  463. (*descriptions)[count] = 0;
  464. } else {
  465. int l;
  466. l = (count + 1) * sizeof (char *);
  467. *descriptions = malloc (l + dcount);
  468. memcpy (*descriptions + l, data, dcount);
  469. XFree (data);
  470. data = (unsigned char *) *descriptions;
  471. data += l;
  472. l = 0;
  473. for (i = 0, r = data;; r += l + 1, i++) {
  474. l = strlen ((char *) r);
  475. if (!l || i >= count)
  476. break;
  477. (*descriptions)[i] = (char *) r;
  478. }
  479. for (; i < count; i++) {
  480. (*descriptions)[i] = "";
  481. }
  482. (*descriptions)[count] = 0;
  483. }
  484. return 0;
  485. }
  486. /* returns non-zero on cancel */
  487. int xdnd_choose_action_dialog (DndClass * dnd, Atom * actions, char **descriptions, Atom * result)
  488. {
  489. if (!actions[0])
  490. return 1;
  491. if (!dnd->action_choose_dialog) { /* default to return the first action if no dialog set */
  492. *result = actions[0];
  493. return 0;
  494. }
  495. return (*dnd->action_choose_dialog) (dnd, descriptions, actions, result);
  496. }
  497. static void xdnd_send_event (DndClass * dnd, Window window, XEvent * xevent)
  498. {
  499. dnd_debug4 ("xdnd_send_event(), window = %ld, l[0] = %ld, l[4] = %ld",
  500. window, xevent->xclient.data.l[0], xevent->xclient.data.l[4]);
  501. dnd_debug2 ("xdnd_send_event(), from widget widget %s", (char *) "<WIDGET>");
  502. XSendEvent (dnd->display, window, 0, 0, xevent);
  503. }
  504. static void xdnd_send_enter (DndClass * dnd, Window window, Window from, Atom * typelist)
  505. {
  506. XEvent xevent;
  507. int n, i;
  508. n = array_length (typelist);
  509. memset (&xevent, 0, sizeof (xevent));
  510. xevent.xany.type = ClientMessage;
  511. xevent.xany.display = dnd->display;
  512. xevent.xclient.window = window;
  513. xevent.xclient.message_type = dnd->XdndEnter;
  514. xevent.xclient.format = 32;
  515. XDND_ENTER_SOURCE_WIN (&xevent) = from;
  516. XDND_ENTER_THREE_TYPES_SET (&xevent, n > XDND_THREE);
  517. XDND_ENTER_VERSION_SET (&xevent, dnd->version);
  518. for (i = 0; i < n && i < XDND_THREE; i++)
  519. XDND_ENTER_TYPE (&xevent, i) = typelist[i];
  520. xdnd_send_event (dnd, window, &xevent);
  521. }
  522. static void xdnd_send_position (DndClass * dnd, Window window, Window from, Atom action, int x, int y, unsigned long time)
  523. {
  524. XEvent xevent;
  525. memset (&xevent, 0, sizeof (xevent));
  526. xevent.xany.type = ClientMessage;
  527. xevent.xany.display = dnd->display;
  528. xevent.xclient.window = window;
  529. xevent.xclient.message_type = dnd->XdndPosition;
  530. xevent.xclient.format = 32;
  531. XDND_POSITION_SOURCE_WIN (&xevent) = from;
  532. XDND_POSITION_ROOT_SET (&xevent, x, y);
  533. if (dnd_version_at_least (dnd->dragging_version, 1))
  534. XDND_POSITION_TIME (&xevent) = time;
  535. if (dnd_version_at_least (dnd->dragging_version, 2))
  536. XDND_POSITION_ACTION (&xevent) = action;
  537. xdnd_send_event (dnd, window, &xevent);
  538. }
  539. static void xdnd_send_status (DndClass * dnd, Window window, Window from, int will_accept, \
  540. int want_position, int x, int y, int w, int h, Atom action)
  541. {
  542. XEvent xevent;
  543. memset (&xevent, 0, sizeof (xevent));
  544. xevent.xany.type = ClientMessage;
  545. xevent.xany.display = dnd->display;
  546. xevent.xclient.window = window;
  547. xevent.xclient.message_type = dnd->XdndStatus;
  548. xevent.xclient.format = 32;
  549. XDND_STATUS_TARGET_WIN (&xevent) = from;
  550. XDND_STATUS_WILL_ACCEPT_SET (&xevent, will_accept);
  551. if (will_accept)
  552. XDND_STATUS_WANT_POSITION_SET (&xevent, want_position);
  553. if (want_position)
  554. XDND_STATUS_RECT_SET (&xevent, x, y, w, h);
  555. if (dnd_version_at_least (dnd->dragging_version, 2))
  556. if (will_accept)
  557. XDND_STATUS_ACTION (&xevent) = action;
  558. xdnd_send_event (dnd, window, &xevent);
  559. }
  560. static void xdnd_send_leave (DndClass * dnd, Window window, Window from)
  561. {
  562. XEvent xevent;
  563. memset (&xevent, 0, sizeof (xevent));
  564. xevent.xany.type = ClientMessage;
  565. xevent.xany.display = dnd->display;
  566. xevent.xclient.window = window;
  567. xevent.xclient.message_type = dnd->XdndLeave;
  568. xevent.xclient.format = 32;
  569. XDND_LEAVE_SOURCE_WIN (&xevent) = from;
  570. xdnd_send_event (dnd, window, &xevent);
  571. }
  572. static void xdnd_send_drop (DndClass * dnd, Window window, Window from, unsigned long time)
  573. {
  574. XEvent xevent;
  575. memset (&xevent, 0, sizeof (xevent));
  576. xevent.xany.type = ClientMessage;
  577. xevent.xany.display = dnd->display;
  578. xevent.xclient.window = window;
  579. xevent.xclient.message_type = dnd->XdndDrop;
  580. xevent.xclient.format = 32;
  581. XDND_DROP_SOURCE_WIN (&xevent) = from;
  582. if (dnd_version_at_least (dnd->dragging_version, 1))
  583. XDND_DROP_TIME (&xevent) = time;
  584. xdnd_send_event (dnd, window, &xevent);
  585. }
  586. /* error is not actually used, i think future versions of the protocol should return an error status
  587. to the calling window with the XdndFinished client message */
  588. static void xdnd_send_finished (DndClass * dnd, Window window, Window from, int error)
  589. {
  590. XEvent xevent;
  591. memset (&xevent, 0, sizeof (xevent));
  592. xevent.xany.type = ClientMessage;
  593. xevent.xany.display = dnd->display;
  594. xevent.xclient.window = window;
  595. xevent.xclient.message_type = dnd->XdndFinished;
  596. xevent.xclient.format = 32;
  597. XDND_FINISHED_TARGET_WIN (&xevent) = from;
  598. xdnd_send_event (dnd, window, &xevent);
  599. }
  600. /* returns non-zero on error - i.e. no selection owner set. Type is of course the mime type */
  601. static int xdnd_convert_selection (DndClass * dnd, Window window, Window requester, Atom type)
  602. {
  603. if (!(window = XGetSelectionOwner (dnd->display, dnd->XdndSelection))) {
  604. dnd_debug1 ("xdnd_convert_selection(): XGetSelectionOwner failed");
  605. return 1;
  606. }
  607. XConvertSelection (dnd->display, dnd->XdndSelection, type,
  608. dnd->Xdnd_NON_PROTOCOL_ATOM, requester, CurrentTime);
  609. return 0;
  610. }
  611. /* returns non-zero on error */
  612. static int xdnd_set_selection_owner (DndClass * dnd, Window window, Atom type, Time time)
  613. {
  614. if (!XSetSelectionOwner (dnd->display, dnd->XdndSelection, window, time)) {
  615. dnd_debug1 ("xdnd_set_selection_owner(): XSetSelectionOwner failed");
  616. return 1;
  617. }
  618. return 0;
  619. }
  620. static void xdnd_selection_send (DndClass * dnd, XSelectionRequestEvent * request, unsigned char *data, int length)
  621. {
  622. XEvent xevent;
  623. dnd_debug2 (" requestor = %ld", request->requestor);
  624. dnd_debug2 (" property = %ld", request->property);
  625. dnd_debug2 (" length = %d", length);
  626. XChangeProperty (dnd->display, request->requestor, request->property,
  627. request->target, 8, PropModeReplace, data, length);
  628. xevent.xselection.type = SelectionNotify;
  629. xevent.xselection.property = request->property;
  630. xevent.xselection.display = request->display;
  631. xevent.xselection.requestor = request->requestor;
  632. xevent.xselection.selection = request->selection;
  633. xevent.xselection.target = request->target;
  634. xevent.xselection.time = request->time;
  635. xdnd_send_event (dnd, request->requestor, &xevent);
  636. }
  637. #if 0
  638. /* respond to a notification that a primary selection has been sent */
  639. int xdnd_get_selection (DndClass * dnd, Window from, Atom property, Window insert)
  640. {
  641. long read;
  642. int error = 0;
  643. unsigned long remaining;
  644. if (!property)
  645. return 1;
  646. read = 0;
  647. do {
  648. unsigned char *s;
  649. Atom actual;
  650. int format;
  651. unsigned long count;
  652. if (XGetWindowProperty (dnd->display, insert, property, read / 4, 65536, 1,
  653. AnyPropertyType, &actual, &format,
  654. &count, &remaining,
  655. &s) != Success) {
  656. XFree (s);
  657. return 1;
  658. }
  659. read += count;
  660. if (dnd->widget_insert_drop && !error)
  661. error = (*dnd->widget_insert_drop) (dnd, s, count, remaining, insert, from, actual);
  662. XFree (s);
  663. } while (remaining);
  664. return error;
  665. }
  666. #endif
  667. static int paste_prop_internal (DndClass * dnd, Window from, Window insert, unsigned long prop, int delete_prop)
  668. {
  669. long nread = 0;
  670. unsigned long nitems;
  671. unsigned long bytes_after;
  672. int error = 0;
  673. do {
  674. Atom actual_type;
  675. int actual_fmt;
  676. unsigned char *s = 0;
  677. if (XGetWindowProperty (dnd->display, insert, prop,
  678. nread / 4, 65536, delete_prop,
  679. AnyPropertyType, &actual_type, &actual_fmt,
  680. &nitems, &bytes_after, &s) != Success) {
  681. XFree (s);
  682. return 1;
  683. }
  684. nread += nitems;
  685. if (dnd->widget_insert_drop && !error)
  686. error = (*dnd->widget_insert_drop) (dnd, s, nitems, bytes_after, insert, from, actual_fmt);
  687. XFree (s);
  688. } while (bytes_after);
  689. if (!nread)
  690. return 1;
  691. return 0;
  692. }
  693. /*
  694. * Respond to a notification that a primary selection has been sent (supports INCR)
  695. */
  696. static int xdnd_get_selection (DndClass * dnd, Window from, Atom prop, Window insert)
  697. {
  698. struct timeval tv, tv_start;
  699. unsigned long bytes_after;
  700. Atom actual_type;
  701. int actual_fmt;
  702. unsigned long nitems;
  703. unsigned char *s = 0;
  704. if (prop == None)
  705. return 1;
  706. if (XGetWindowProperty
  707. (dnd->display, insert, prop, 0, 8, False, AnyPropertyType, &actual_type, &actual_fmt,
  708. &nitems, &bytes_after, &s) != Success) {
  709. XFree (s);
  710. return 1;
  711. }
  712. XFree (s);
  713. if (actual_type != XInternAtom (dnd->display, "INCR", False))
  714. return paste_prop_internal (dnd, from, insert, prop, True);
  715. XDeleteProperty (dnd->display, insert, prop);
  716. gettimeofday (&tv_start, 0);
  717. for (;;) {
  718. long t;
  719. fd_set r;
  720. XEvent xe;
  721. if (XCheckMaskEvent (dnd->display, PropertyChangeMask, &xe)) {
  722. if (xe.type == PropertyNotify && xe.xproperty.state == PropertyNewValue) {
  723. /* time between arrivals of data */
  724. gettimeofday (&tv_start, 0);
  725. if (paste_prop_internal (dnd, from, insert, prop, True))
  726. break;
  727. }
  728. } else {
  729. tv.tv_sec = 0;
  730. tv.tv_usec = 10000;
  731. FD_ZERO (&r);
  732. FD_SET (ConnectionNumber (dnd->display), &r);
  733. select (ConnectionNumber (dnd->display) + 1, &r, 0, 0, &tv);
  734. if (FD_ISSET (ConnectionNumber (dnd->display), &r))
  735. continue;
  736. }
  737. gettimeofday (&tv, 0);
  738. t = (tv.tv_sec - tv_start.tv_sec) * 1000000L + (tv.tv_usec - tv_start.tv_usec);
  739. /* no data for five seconds, so quit */
  740. if (t > 5000000L)
  741. return 1;
  742. }
  743. return 0;
  744. }
  745. int outside_rectangle (int x, int y, XRectangle * r)
  746. {
  747. return (x < r->x || y < r->y || x >= r->x + r->width || y >= r->y + r->height);
  748. }
  749. /* avoids linking with the maths library */
  750. static float xdnd_sqrt (float x)
  751. {
  752. float last_ans, ans = 2, a;
  753. if (x <= 0.0)
  754. return 0.0;
  755. do {
  756. last_ans = ans;
  757. ans = (ans + x / ans) / 2;
  758. a = (ans - last_ans) / ans;
  759. if (a < 0.0)
  760. a = (-a);
  761. } while (a > 0.001);
  762. return ans;
  763. }
  764. #define print_marks print_win_marks(from,__FILE__,__LINE__);
  765. /* returns action on success, 0 otherwise */
  766. Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist)
  767. {
  768. XEvent xevent, xevent_temp;
  769. Window over_window = 0, last_window = 0;
  770. #if XDND_VERSION >= 3
  771. Window last_dropper_toplevel = 0;
  772. int internal_dropable = 1;
  773. #endif
  774. int n;
  775. DndCursor *cursor;
  776. float x_mouse, y_mouse;
  777. int result = 0, dnd_aware;
  778. if (!typelist)
  779. dnd_warning ("xdnd_drag() called with typelist = 0");
  780. /* first wait until the mouse moves more than five pixels */
  781. do {
  782. XNextEvent (dnd->display, &xevent);
  783. if (xevent.type == ButtonRelease) {
  784. dnd_debug1 ("button release - no motion");
  785. XSendEvent (dnd->display, xevent.xany.window, 0, ButtonReleaseMask, &xevent);
  786. return 0;
  787. }
  788. } while (xevent.type != MotionNotify);
  789. x_mouse = (float) xevent.xmotion.x_root;
  790. y_mouse = (float) xevent.xmotion.y_root;
  791. if (!dnd->drag_threshold)
  792. dnd->drag_threshold = 4.0;
  793. for (;;) {
  794. XNextEvent (dnd->display, &xevent);
  795. if (xevent.type == MotionNotify)
  796. if (xdnd_sqrt ((x_mouse - xevent.xmotion.x_root) * (x_mouse - xevent.xmotion.x_root) +
  797. (y_mouse - xevent.xmotion.y_root) * (y_mouse - xevent.xmotion.y_root)) > dnd->drag_threshold)
  798. break;
  799. if (xevent.type == ButtonRelease) {
  800. XSendEvent (dnd->display, xevent.xany.window, 0, ButtonReleaseMask, &xevent);
  801. return 0;
  802. }
  803. }
  804. dnd_debug1 ("moved 5 pixels - going to drag");
  805. n = array_length (typelist);
  806. if (n > XDND_THREE)
  807. xdnd_set_type_list (dnd, from, typelist);
  808. xdnd_reset (dnd);
  809. dnd->stage = XDND_DRAG_STAGE_DRAGGING;
  810. for (cursor = &dnd->cursors[0]; cursor->width; cursor++)
  811. if (cursor->action == action)
  812. break;
  813. if (!cursor->width)
  814. cursor = &dnd->cursors[0];
  815. /* the mouse has been dragged a little, so this is a drag proper */
  816. if (XGrabPointer (dnd->display, dnd->root_window, False,
  817. ButtonMotionMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
  818. GrabModeAsync, GrabModeAsync, None,
  819. cursor->cursor, CurrentTime) != GrabSuccess)
  820. dnd_debug1 ("Unable to grab pointer");
  821. while (xevent.xany.type != ButtonRelease) {
  822. XAllowEvents (dnd->display, SyncPointer, CurrentTime);
  823. XNextEvent (dnd->display, &xevent);
  824. switch (xevent.type) {
  825. case Expose:
  826. if (dnd->handle_expose_events)
  827. (*dnd->handle_expose_events) (dnd, &xevent);
  828. break;
  829. case EnterNotify:
  830. /* this event is not actually reported, so we find out by ourselves from motion events */
  831. break;
  832. case LeaveNotify:
  833. /* this event is not actually reported, so we find out by ourselves from motion events */
  834. break;
  835. case ButtonRelease:
  836. /* done, but must send a leave event */
  837. dnd_debug1 ("ButtonRelease - exiting event loop");
  838. break;
  839. case MotionNotify:
  840. dnd_aware = 0;
  841. dnd->dropper_toplevel = 0;
  842. memcpy (&xevent_temp, &xevent, sizeof (xevent));
  843. xevent.xmotion.subwindow = xevent.xmotion.window;
  844. {
  845. Window root_return, child_return;
  846. int x_temp, y_temp;
  847. unsigned int mask_return;
  848. while (XQueryPointer (dnd->display, xevent.xmotion.subwindow, &root_return, &child_return,
  849. &x_temp, &y_temp, &xevent.xmotion.x,
  850. &xevent.xmotion.y, &mask_return)) {
  851. #if XDND_VERSION >= 3
  852. if (!dnd_aware) {
  853. if ((dnd_aware = xdnd_is_dnd_aware (dnd, xevent.xmotion.subwindow, &dnd->dragging_version, typelist))) {
  854. dnd->dropper_toplevel = xevent.xmotion.subwindow;
  855. xevent.xmotion.x_root = x_temp;
  856. xevent.xmotion.y_root = y_temp;
  857. }
  858. }
  859. #else
  860. xevent.xmotion.x_root = x_temp;
  861. xevent.xmotion.y_root = y_temp;
  862. #endif
  863. if (!child_return)
  864. goto found_descendent;
  865. xevent.xmotion.subwindow = child_return;
  866. }
  867. break;
  868. }
  869. found_descendent:
  870. /* last_window is just for debug purposes */
  871. if (last_window != xevent.xmotion.subwindow) {
  872. dnd_debug2 ("window crossing to %ld", xevent.xmotion.subwindow);
  873. dnd_debug2 (" current window is %ld", over_window);
  874. dnd_debug3 (" last_window = %ld, xmotion.subwindow = %ld", last_window, xevent.xmotion.subwindow);
  875. #if XDND_VERSION >= 3
  876. dnd_debug3 (" dropper_toplevel = %ld, last_dropper_toplevel.subwindow = %ld", dnd->dropper_toplevel, last_dropper_toplevel);
  877. #endif
  878. dnd_debug3 (" dnd_aware = %d, dnd->options & XDND_OPTION_NO_HYSTERESIS = %ld", dnd_aware, (long) dnd->options & XDND_OPTION_NO_HYSTERESIS);
  879. }
  880. #if XDND_VERSION < 3
  881. /* is the new window dnd aware? if not stay in the old window */
  882. if (over_window != xevent.xmotion.subwindow &&
  883. last_window != xevent.xmotion.subwindow &&
  884. (
  885. (dnd_aware = xdnd_is_dnd_aware (dnd, xevent.xmotion.subwindow, &dnd->dragging_version, typelist))
  886. ||
  887. (dnd->options & XDND_OPTION_NO_HYSTERESIS)
  888. ))
  889. #else
  890. internal_dropable = 1;
  891. if (dnd->widget_exists && (*dnd->widget_exists) (dnd, xevent.xmotion.subwindow))
  892. if (!xdnd_is_dnd_aware (dnd, xevent.xmotion.subwindow, &dnd->dragging_version, typelist))
  893. internal_dropable = 0;
  894. dnd_debug3 ("dnd->dropper_toplevel = %ld, last_dropper_toplevel = %ld\n", dnd->dropper_toplevel, last_dropper_toplevel);
  895. if ((dnd->dropper_toplevel != last_dropper_toplevel ||
  896. last_window != xevent.xmotion.subwindow) && internal_dropable &&
  897. (
  898. (dnd_aware)
  899. ||
  900. (dnd->options & XDND_OPTION_NO_HYSTERESIS)
  901. ))
  902. #endif
  903. {
  904. /* leaving window we were over */
  905. if (over_window) {
  906. if (dnd->stage == XDND_DRAG_STAGE_ENTERED) {
  907. dnd_debug1 ("got leave at right stage");
  908. dnd->stage = XDND_DRAG_STAGE_DRAGGING;
  909. if (dnd->internal_drag) {
  910. dnd_debug1 (" our own widget");
  911. if (dnd->widget_apply_leave)
  912. (*dnd->widget_apply_leave) (dnd, over_window);
  913. } else {
  914. dnd_debug1 (" not our widget - sending XdndLeave");
  915. #if XDND_VERSION < 3
  916. xdnd_send_leave (dnd, over_window, from);
  917. #else
  918. if (dnd->dropper_toplevel != last_dropper_toplevel) {
  919. xdnd_send_leave (dnd, last_dropper_toplevel, from);
  920. } else {
  921. dnd_debug1 (" not sending leave --> dnd->dropper_toplevel == last_dropper_toplevel");
  922. }
  923. #endif
  924. }
  925. dnd->internal_drag = 0;
  926. dnd->dropper_window = 0;
  927. dnd->ready_to_drop = 0;
  928. } else {
  929. dnd_debug1 ("got leave at wrong stage - ignoring");
  930. }
  931. }
  932. /* entering window we are currently over */
  933. over_window = xevent.xmotion.subwindow;
  934. if (dnd_aware) {
  935. dnd_debug1 (" is dnd aware");
  936. dnd->stage = XDND_DRAG_STAGE_ENTERED;
  937. if (dnd->widget_exists && (*dnd->widget_exists) (dnd, over_window))
  938. dnd->internal_drag = 1;
  939. if (dnd->internal_drag) {
  940. dnd_debug1 (" our own widget");
  941. } else {
  942. dnd_debug2 (" not our widget - sending XdndEnter to %ld", over_window);
  943. #if XDND_VERSION < 3
  944. xdnd_send_enter (dnd, over_window, from, typelist);
  945. #else
  946. if (dnd->dropper_toplevel != last_dropper_toplevel)
  947. xdnd_send_enter (dnd, dnd->dropper_toplevel, from, typelist);
  948. #endif
  949. }
  950. dnd->want_position = 1;
  951. dnd->ready_to_drop = 0;
  952. dnd->rectangle.width = dnd->rectangle.height = 0;
  953. dnd->dropper_window = over_window;
  954. /* we want an additional motion event in case the pointer enters and then stops */
  955. XSendEvent (dnd->display, from, 0, ButtonMotionMask, &xevent_temp);
  956. XSync (dnd->display, 0);
  957. }
  958. #if XDND_VERSION >= 3
  959. last_dropper_toplevel = dnd->dropper_toplevel;
  960. #endif
  961. /* we are now officially in a new window */
  962. } else {
  963. /* got here, so we are just moving `inside' the same window */
  964. if (dnd->stage == XDND_DRAG_STAGE_ENTERED) {
  965. dnd->supported_action = dnd->XdndActionCopy;
  966. dnd_debug1 ("got motion at right stage");
  967. dnd->x = xevent.xmotion.x_root;
  968. dnd->y = xevent.xmotion.y_root;
  969. if (dnd->want_position || outside_rectangle (dnd->x, dnd->y, &dnd->rectangle)) {
  970. dnd_debug1 (" want position and outside rectangle");
  971. if (dnd->internal_drag) {
  972. dnd_debug1 (" our own widget");
  973. dnd->ready_to_drop = (*dnd->widget_apply_position) (dnd, over_window, from,
  974. action, dnd->x, dnd->y, xevent.xmotion.time, typelist,
  975. &dnd->want_position, &dnd->supported_action, &dnd->desired_type, &dnd->rectangle);
  976. /* if not ready, keep sending positions, this check is repeated below for XdndStatus from external widgets */
  977. if (!dnd->ready_to_drop) {
  978. dnd->want_position = 1;
  979. dnd->rectangle.width = dnd->rectangle.height = 0;
  980. }
  981. dnd_debug2 (" return action=%ld", dnd->supported_action);
  982. } else {
  983. #if XDND_VERSION < 3
  984. dnd_debug3 (" not our own widget - sending XdndPosition to %ld, action %ld", over_window, action);
  985. xdnd_send_position (dnd, over_window, from, action, dnd->x, dnd->y, xevent.xmotion.time);
  986. #else
  987. dnd_debug3 (" not our own widget - sending XdndPosition to %ld, action %ld", dnd->dropper_toplevel, action);
  988. xdnd_send_position (dnd, dnd->dropper_toplevel, from, action, dnd->x, dnd->y, xevent.xmotion.time);
  989. #endif
  990. }
  991. } else if (dnd->want_position) {
  992. dnd_debug1 (" inside rectangle");
  993. } else {
  994. dnd_debug1 (" doesn't want position");
  995. }
  996. }
  997. }
  998. last_window = xevent.xmotion.subwindow;
  999. break;
  1000. case ClientMessage:
  1001. dnd_debug1 ("ClientMessage recieved");
  1002. if (xevent.xclient.message_type == dnd->XdndStatus && !dnd->internal_drag) {
  1003. dnd_debug1 (" XdndStatus recieved");
  1004. if (dnd->stage == XDND_DRAG_STAGE_ENTERED
  1005. #if XDND_VERSION < 3
  1006. && XDND_STATUS_TARGET_WIN (&xevent) == dnd->dropper_window
  1007. #endif
  1008. ) {
  1009. dnd_debug1 (" XdndStatus stage correct, dropper window correct");
  1010. dnd->want_position = XDND_STATUS_WANT_POSITION (&xevent);
  1011. dnd->ready_to_drop = XDND_STATUS_WILL_ACCEPT (&xevent);
  1012. dnd->rectangle.x = XDND_STATUS_RECT_X (&xevent);
  1013. dnd->rectangle.y = XDND_STATUS_RECT_Y (&xevent);
  1014. dnd->rectangle.width = XDND_STATUS_RECT_WIDTH (&xevent);
  1015. dnd->rectangle.height = XDND_STATUS_RECT_HEIGHT (&xevent);
  1016. dnd->supported_action = dnd->XdndActionCopy;
  1017. if (dnd_version_at_least (dnd->dragging_version, 2))
  1018. dnd->supported_action = XDND_STATUS_ACTION (&xevent);
  1019. dnd_debug3 (" return action=%ld, ready=%d", dnd->supported_action, dnd->ready_to_drop);
  1020. /* if not ready, keep sending positions, this check is repeated above for internal widgets */
  1021. if (!dnd->ready_to_drop) {
  1022. dnd->want_position = 1;
  1023. dnd->rectangle.width = dnd->rectangle.height = 0;
  1024. }
  1025. dnd_debug3 (" rectangle = (x=%d, y=%d, ", dnd->rectangle.x, dnd->rectangle.y);
  1026. dnd_debug4 ("w=%d, h=%d), want_position=%d\n", dnd->rectangle.width, dnd->rectangle.height, dnd->want_position);
  1027. }
  1028. #if XDND_VERSION < 3
  1029. else if (XDND_STATUS_TARGET_WIN (&xevent) != dnd->dropper_window) {
  1030. dnd_debug3 (" XdndStatus XDND_STATUS_TARGET_WIN (&xevent) = %ld, dnd->dropper_window = %ld", XDND_STATUS_TARGET_WIN (&xevent), dnd->dropper_window);
  1031. }
  1032. #endif
  1033. else {
  1034. dnd_debug2 (" XdndStatus stage incorrect dnd->stage = %d", dnd->stage);
  1035. }
  1036. }
  1037. break;
  1038. case SelectionRequest:{
  1039. /* the target widget MAY request data, so wait for SelectionRequest */
  1040. int length = 0;
  1041. unsigned char *data = 0;
  1042. dnd_debug1 ("SelectionRequest - getting widget data");
  1043. (*dnd->widget_get_data) (dnd, from, &data, &length, xevent.xselectionrequest.target);
  1044. if (data) {
  1045. dnd_debug1 (" sending selection");
  1046. xdnd_selection_send (dnd, &xevent.xselectionrequest, data, length);
  1047. xdnd_xfree (data);
  1048. }
  1049. }
  1050. break;
  1051. }
  1052. }
  1053. if (dnd->ready_to_drop) {
  1054. Time time;
  1055. dnd_debug1 ("ready_to_drop - sending XdndDrop");
  1056. time = xevent.xbutton.time;
  1057. if (dnd->internal_drag) {
  1058. /* we are dealing with our own widget, no need to send drop events, just put the data straight */
  1059. int length = 0;
  1060. unsigned char *data = 0;
  1061. if (dnd->widget_insert_drop) {
  1062. (*dnd->widget_get_data) (dnd, from, &data, &length, dnd->desired_type);
  1063. if (data) {
  1064. if (!(*dnd->widget_insert_drop) (dnd, data, length, 0, dnd->dropper_window, from, dnd->desired_type)) {
  1065. result = dnd->supported_action; /* success - so return action to caller */
  1066. dnd_debug1 (" inserted data into widget - success");
  1067. } else {
  1068. dnd_debug1 (" inserted data into widget - failed");
  1069. }
  1070. xdnd_xfree (data);
  1071. } else {
  1072. dnd_debug1 (" got data from widget, but data is null");
  1073. }
  1074. }
  1075. } else {
  1076. xdnd_set_selection_owner (dnd, from, dnd->desired_type, time);
  1077. #if XDND_VERSION < 3
  1078. xdnd_send_drop (dnd, dnd->dropper_window, from, time);
  1079. #else
  1080. xdnd_send_drop (dnd, dnd->dropper_toplevel, from, time);
  1081. #endif
  1082. }
  1083. if (!dnd->internal_drag)
  1084. for (;;) {
  1085. XAllowEvents (dnd->display, SyncPointer, CurrentTime);
  1086. XNextEvent (dnd->display, &xevent);
  1087. if (xevent.type == ClientMessage && xevent.xclient.message_type == dnd->XdndFinished) {
  1088. dnd_debug1 ("XdndFinished");
  1089. #if XDND_VERSION < 3
  1090. if (XDND_FINISHED_TARGET_WIN (&xevent) == dnd->dropper_window) {
  1091. #endif
  1092. dnd_debug2 (" source correct - exiting event loop, action=%ld", dnd->supported_action);
  1093. result = dnd->supported_action; /* success - so return action to caller */
  1094. break;
  1095. #if XDND_VERSION < 3
  1096. }
  1097. #endif
  1098. } else if (xevent.type == Expose) {
  1099. if (dnd->handle_expose_events)
  1100. (*dnd->handle_expose_events) (dnd, &xevent);
  1101. } else if (xevent.type == MotionNotify) {
  1102. if (xevent.xmotion.time > time + (dnd->time_out ? dnd->time_out * 1000 : 10000)) { /* allow a ten second timeout as default */
  1103. dnd_debug1 ("timeout - exiting event loop");
  1104. break;
  1105. }
  1106. } else if (xevent.type == SelectionRequest && xevent.xselectionrequest.selection == dnd->XdndSelection) {
  1107. /* the target widget is going to request data, so check for SelectionRequest events */
  1108. int length = 0;
  1109. unsigned char *data = 0;
  1110. dnd_debug1 ("SelectionRequest - getting widget data");
  1111. (*dnd->widget_get_data) (dnd, from, &data, &length, xevent.xselectionrequest.target);
  1112. if (data) {
  1113. dnd_debug1 (" sending selection");
  1114. xdnd_selection_send (dnd, &xevent.xselectionrequest, data, length);
  1115. xdnd_xfree (data);
  1116. }
  1117. /* don't wait for a XdndFinished event */
  1118. if (!dnd_version_at_least (dnd->dragging_version, 2))
  1119. break;
  1120. }
  1121. }
  1122. } else {
  1123. dnd_debug1 ("not ready_to_drop - ungrabbing pointer");
  1124. }
  1125. XUngrabPointer (dnd->display, CurrentTime);
  1126. xdnd_reset (dnd);
  1127. return result;
  1128. }
  1129. /* returns non-zero if event is handled */
  1130. int xdnd_handle_drop_events (DndClass * dnd, XEvent * xevent)
  1131. {
  1132. int result = 0;
  1133. if (xevent->type == SelectionNotify) {
  1134. dnd_debug1 ("got SelectionNotify");
  1135. if (xevent->xselection.property == dnd->Xdnd_NON_PROTOCOL_ATOM && dnd->stage == XDND_DROP_STAGE_CONVERTING) {
  1136. int error;
  1137. dnd_debug1 (" property is Xdnd_NON_PROTOCOL_ATOM - getting selection");
  1138. error = xdnd_get_selection (dnd, dnd->dragger_window, xevent->xselection.property, xevent->xany.window);
  1139. /* error is not actually used, i think future versions of the protocol maybe should return
  1140. an error status to the calling window with the XdndFinished client message */
  1141. if (dnd_version_at_least (dnd->dragging_version, 2)) {
  1142. #if XDND_VERSION >= 3
  1143. xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, error);
  1144. #else
  1145. xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_window, error);
  1146. #endif
  1147. dnd_debug1 (" sending finished");
  1148. }
  1149. xdnd_xfree (dnd->dragger_typelist);
  1150. xdnd_reset (dnd);
  1151. dnd->stage = XDND_DROP_STAGE_IDLE;
  1152. result = 1;
  1153. } else {
  1154. dnd_debug1 (" property is not Xdnd_NON_PROTOCOL_ATOM - ignoring");
  1155. }
  1156. } else if (xevent->type == ClientMessage) {
  1157. dnd_debug2 ("got ClientMessage to xevent->xany.window = %ld", xevent->xany.window);
  1158. if (xevent->xclient.message_type == dnd->XdndEnter) {
  1159. dnd_debug2 (" message_type is XdndEnter, version = %ld", XDND_ENTER_VERSION (xevent));
  1160. #if XDND_VERSION >= 3
  1161. if (XDND_ENTER_VERSION (xevent) < 3)
  1162. return 0;
  1163. #endif
  1164. xdnd_reset (dnd);
  1165. dnd->dragger_window = XDND_ENTER_SOURCE_WIN (xevent);
  1166. #if XDND_VERSION >= 3
  1167. dnd->dropper_toplevel = xevent->xany.window;
  1168. dnd->dropper_window = 0; /* enter goes to the top level window only,
  1169. so we don't really know what the
  1170. sub window is yet */
  1171. #else
  1172. dnd->dropper_window = xevent->xany.window;
  1173. #endif
  1174. xdnd_xfree (dnd->dragger_typelist);
  1175. if (XDND_ENTER_THREE_TYPES (xevent)) {
  1176. dnd_debug1 (" three types only");
  1177. xdnd_get_three_types (dnd, xevent, &dnd->dragger_typelist);
  1178. } else {
  1179. dnd_debug1 (" more than three types - getting list");
  1180. xdnd_get_type_list (dnd, dnd->dragger_window, &dnd->dragger_typelist);
  1181. }
  1182. if (dnd->dragger_typelist)
  1183. dnd->stage = XDND_DROP_STAGE_ENTERED;
  1184. else
  1185. dnd_debug1 (" typelist returned as zero!");
  1186. dnd->dragging_version = XDND_ENTER_VERSION (xevent);
  1187. result = 1;
  1188. } else if (xevent->xclient.message_type == dnd->XdndLeave) {
  1189. #if XDND_VERSION >= 3
  1190. if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
  1191. xevent->xany.window = dnd->dropper_window;
  1192. #endif
  1193. dnd_debug1 (" message_type is XdndLeave");
  1194. if (dnd->dragger_window == XDND_LEAVE_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
  1195. dnd_debug1 (" leaving");
  1196. if (dnd->widget_apply_leave)
  1197. (*dnd->widget_apply_leave) (dnd, xevent->xany.window);
  1198. dnd->stage = XDND_DROP_STAGE_IDLE;
  1199. xdnd_xfree (dnd->dragger_typelist);
  1200. result = 1;
  1201. dnd->dropper_toplevel = dnd->dropper_window = 0;
  1202. } else {
  1203. dnd_debug1 (" wrong stage or from wrong window");
  1204. }
  1205. } else if (xevent->xclient.message_type == dnd->XdndPosition) {
  1206. dnd_debug2 (" message_type is XdndPosition to %ld", xevent->xany.window);
  1207. if (dnd->dragger_window == XDND_POSITION_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
  1208. int want_position;
  1209. Atom action;
  1210. XRectangle rectangle;
  1211. Window last_window;
  1212. last_window = dnd->dropper_window;
  1213. #if XDND_VERSION >= 3
  1214. /* version 3 gives us the top-level window only. WE have to find the child that the pointer is over: */
  1215. if (1 || xevent->xany.window != dnd->dropper_toplevel || !dnd->dropper_window) {
  1216. Window parent, child, new_child = 0;
  1217. dnd->dropper_toplevel = xevent->xany.window;
  1218. parent = dnd->root_window;
  1219. child = dnd->dropper_toplevel;
  1220. for (;;) {
  1221. int xd, yd;
  1222. new_child = 0;
  1223. if (!XTranslateCoordinates (dnd->display, parent, child,
  1224. XDND_POSITION_ROOT_X (xevent), XDND_POSITION_ROOT_Y (xevent),
  1225. &xd, &yd, &new_child))
  1226. break;
  1227. if (!new_child)
  1228. break;
  1229. child = new_child;
  1230. }
  1231. dnd->dropper_window = xevent->xany.window = child;
  1232. dnd_debug2 (" child window translates to %ld", dnd->dropper_window);
  1233. } else if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window) {
  1234. xevent->xany.window = dnd->dropper_window;
  1235. dnd_debug2 (" child window previously found: %ld", dnd->dropper_window);
  1236. }
  1237. #endif
  1238. action = dnd->XdndActionCopy;
  1239. dnd->supported_action = dnd->XdndActionCopy;
  1240. dnd->x = XDND_POSITION_ROOT_X (xevent);
  1241. dnd->y = XDND_POSITION_ROOT_Y (xevent);
  1242. dnd->time = CurrentTime;
  1243. if (dnd_version_at_least (dnd->dragging_version, 1))
  1244. dnd->time = XDND_POSITION_TIME (xevent);
  1245. if (dnd_version_at_least (dnd->dragging_version, 1))
  1246. action = XDND_POSITION_ACTION (xevent);
  1247. #if XDND_VERSION >= 3
  1248. if (last_window && last_window != xevent->xany.window)
  1249. if (dnd->widget_apply_leave)
  1250. (*dnd->widget_apply_leave) (dnd, last_window);
  1251. #endif
  1252. dnd->will_accept = (*dnd->widget_apply_position) (dnd, xevent->xany.window, dnd->dragger_window,
  1253. action, dnd->x, dnd->y, dnd->time, dnd->dragger_typelist,
  1254. &want_position, &dnd->supported_action, &dnd->desired_type, &rectangle);
  1255. dnd_debug2 (" will accept = %d", dnd->will_accept);
  1256. #if XDND_VERSION >= 3
  1257. dnd_debug2 (" sending status of %ld", dnd->dropper_toplevel);
  1258. xdnd_send_status (dnd, dnd->dragger_window, dnd->dropper_toplevel, dnd->will_accept,
  1259. want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
  1260. #else
  1261. dnd_debug2 (" sending status of %ld", xevent->xany.window);
  1262. xdnd_send_status (dnd, dnd->dragger_window, xevent->xany.window, dnd->will_accept,
  1263. want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
  1264. #endif
  1265. result = 1;
  1266. } else {
  1267. dnd_debug1 (" wrong stage or from wrong window");
  1268. }
  1269. } else if (xevent->xclient.message_type == dnd->XdndDrop) {
  1270. #if XDND_VERSION >= 3
  1271. if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
  1272. xevent->xany.window = dnd->dropper_window;
  1273. #endif
  1274. dnd_debug1 (" message_type is XdndDrop");
  1275. if (dnd->dragger_window == XDND_DROP_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
  1276. dnd->time = CurrentTime;
  1277. if (dnd_version_at_least (dnd->dragging_version, 1))
  1278. dnd->time = XDND_DROP_TIME (xevent);
  1279. if (dnd->will_accept) {
  1280. dnd_debug1 (" will_accept is true - converting selectiong");
  1281. dnd_debug2 (" my window is %ld", dnd->dropper_window);
  1282. dnd_debug2 (" source window is %ld", dnd->dragger_window);
  1283. xdnd_convert_selection (dnd, dnd->dragger_window, dnd->dropper_window, dnd->desired_type);
  1284. dnd->stage = XDND_DROP_STAGE_CONVERTING;
  1285. } else {
  1286. dnd_debug1 (" will_accept is false - sending finished");
  1287. if (dnd_version_at_least (dnd->dragging_version, 2)) {
  1288. #if XDND_VERSION >= 3
  1289. xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, 1);
  1290. #else
  1291. xdnd_send_finished (dnd, dnd->dragger_window, xevent->xany.window, 1);
  1292. #endif
  1293. }
  1294. xdnd_xfree (dnd->dragger_typelist);
  1295. xdnd_reset (dnd);
  1296. dnd->stage = XDND_DROP_STAGE_IDLE;
  1297. }
  1298. result = 1;
  1299. } else {
  1300. dnd_debug1 (" wrong stage or from wrong window");
  1301. }
  1302. }
  1303. }
  1304. return result;
  1305. }
  1306. /*
  1307. Following here is a sample implementation: Suppose we want a window
  1308. to recieve drops, but do not want to be concerned with setting up all
  1309. the DndClass methods. All we then do is call xdnd_get_drop() whenever a
  1310. ClientMessage is recieved. If the message has nothing to do with XDND,
  1311. xdnd_get_drop quickly returns 0. If it is a XdndEnter message, then
  1312. xdnd_get_drop enters its own XNextEvent loop and handles all XDND
  1313. protocol messages internally, returning the action requested.
  1314. You should pass a desired typelist and actionlist to xdnd_get_type.
  1315. These must be null terminated arrays of atoms, or a null pointer
  1316. if you would like any action or type to be accepted. If typelist
  1317. is null then the first type of the dragging widgets typelist will
  1318. be the one used. If actionlist is null, then only XdndActionCopy will
  1319. be accepted.
  1320. The result is stored in *data, length, type, x and y.
  1321. *data must be free'd.
  1322. */
  1323. struct xdnd_get_drop_info {
  1324. unsigned char *drop_data;
  1325. int drop_data_length;
  1326. int x, y;
  1327. Atom return_type;
  1328. Atom return_action;
  1329. Atom *typelist;
  1330. Atom *actionlist;
  1331. };
  1332. static int widget_insert_drop (DndClass * dnd, unsigned char *data, int length, int remaining, Window into, Window from, Atom type)
  1333. {
  1334. struct xdnd_get_drop_info *i;
  1335. i = (struct xdnd_get_drop_info *) dnd->user_hook1;
  1336. if (!i->drop_data) {
  1337. i->drop_data = malloc (length);
  1338. if (!i->drop_data)
  1339. return 1;
  1340. memcpy (i->drop_data, data, length);
  1341. i->drop_data_length = length;
  1342. } else {
  1343. unsigned char *t;
  1344. t = malloc (i->drop_data_length + length);
  1345. if (!t) {
  1346. free (i->drop_data);
  1347. i->drop_data = 0;
  1348. return 1;
  1349. }
  1350. memcpy (t, i->drop_data, i->drop_data_length);
  1351. memcpy (t + i->drop_data_length, data, length);
  1352. free (i->drop_data);
  1353. i->drop_data = t;
  1354. i->drop_data_length += length;
  1355. }
  1356. return 0;
  1357. }
  1358. static int widget_apply_position (DndClass * dnd, Window widgets_window, Window from,
  1359. Atom action, int x, int y, Time t, Atom * typelist,
  1360. int *want_position, Atom * supported_action_return, Atom * desired_type,
  1361. XRectangle * rectangle)
  1362. {
  1363. int i, j;
  1364. struct xdnd_get_drop_info *info;
  1365. Atom *dropper_typelist, supported_type = 0;
  1366. Atom *supported_actions, supported_action = 0;
  1367. info = (struct xdnd_get_drop_info *) dnd->user_hook1;
  1368. dropper_typelist = info->typelist;
  1369. supported_actions = info->actionlist;
  1370. if (dropper_typelist) {
  1371. /* find a correlation: */
  1372. for (j = 0; dropper_typelist[j]; j++) {
  1373. for (i = 0; typelist[i]; i++) {
  1374. if (typelist[i] == dropper_typelist[j]) {
  1375. supported_type = typelist[i];
  1376. break;
  1377. }
  1378. }
  1379. if (supported_type)
  1380. break;
  1381. }
  1382. } else {
  1383. /* user did not specify, so return first type */
  1384. supported_type = typelist[0];
  1385. }
  1386. /* not supported, so return false */
  1387. if (!supported_type)
  1388. return 0;
  1389. if (supported_actions) {
  1390. for (j = 0; supported_actions[j]; j++) {
  1391. if (action == supported_actions[j]) {
  1392. supported_action = action;
  1393. break;
  1394. }
  1395. }
  1396. } else {
  1397. /* user did not specify */
  1398. if (action == dnd->XdndActionCopy)
  1399. supported_action = action;
  1400. }
  1401. if (!supported_action)
  1402. return 0;
  1403. *want_position = 1;
  1404. rectangle->x = rectangle->y = 0;
  1405. rectangle->width = rectangle->height = 0;
  1406. info->return_action = *supported_action_return = supported_action;
  1407. info->return_type = *desired_type = supported_type;
  1408. info->x = x;
  1409. info->y = y;
  1410. return 1;
  1411. }
  1412. Atom xdnd_get_drop (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
  1413. unsigned char **data, int *length, Atom * type, int *x, int *y)
  1414. {
  1415. Atom action = 0;
  1416. static int initialised = 0;
  1417. static DndClass dnd;
  1418. if (!initialised) {
  1419. xdnd_init (&dnd, display);
  1420. initialised = 1;
  1421. }
  1422. if (xevent->type != ClientMessage || xevent->xclient.message_type != dnd.XdndEnter) {
  1423. return 0;
  1424. } else {
  1425. struct xdnd_get_drop_info i;
  1426. /* setup user structure */
  1427. memset (&i, 0, sizeof (i));
  1428. i.actionlist = actionlist;
  1429. i.typelist = typelist;
  1430. dnd.user_hook1 = &i;
  1431. /* setup methods */
  1432. dnd.widget_insert_drop = widget_insert_drop;
  1433. dnd.widget_apply_position = widget_apply_position;
  1434. /* main loop */
  1435. for (;;) {
  1436. xdnd_handle_drop_events (&dnd, xevent);
  1437. if (dnd.stage == XDND_DROP_STAGE_IDLE)
  1438. break;
  1439. XNextEvent (dnd.display, xevent);
  1440. }
  1441. /* return results */
  1442. if (i.drop_data) {
  1443. *length = i.drop_data_length;
  1444. *data = i.drop_data;
  1445. action = i.return_action;
  1446. *type = i.return_type;
  1447. *x = i.x;
  1448. *y = i.y;
  1449. }
  1450. }
  1451. return action;
  1452. }