Blender V4.3
GHOST_DropTargetX11.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include "GHOST_Debug.hh"
11#include "GHOST_PathUtils.hh"
12#include "GHOST_utildefines.hh"
13
14#include <cassert>
15#include <cctype>
16#include <cstdio>
17#include <cstring>
18
19bool GHOST_DropTargetX11::m_xdndInitialized = false;
20DndClass GHOST_DropTargetX11::m_dndClass;
21Atom *GHOST_DropTargetX11::m_dndTypes = nullptr;
22Atom *GHOST_DropTargetX11::m_dndActions = nullptr;
23const char *GHOST_DropTargetX11::m_dndMimeTypes[] = {
24 "url/url", "text/uri-list", "text/plain", "application/octet-stream"};
25int GHOST_DropTargetX11::m_refCounter = 0;
26
27#define dndTypeURLID 0
28#define dndTypeURIListID 1
29#define dndTypePlainTextID 2
30#define dndTypeOctetStreamID 3
31
32#define dndTypeURL m_dndTypes[dndTypeURLID]
33#define dndTypeURIList m_dndTypes[dndTypeURIListID]
34#define dndTypePlainText m_dndTypes[dndTypePlainTextID]
35#define dndTypeOctetStream m_dndTypes[dndTypeOctetStreamID]
36
37void GHOST_DropTargetX11::Initialize()
38{
39 Display *display = m_system->getXDisplay();
40 int dndTypesCount = ARRAY_SIZE(m_dndMimeTypes);
41 int counter;
42
43 xdnd_init(&m_dndClass, display);
44
45 m_dndTypes = new Atom[dndTypesCount + 1];
46 XInternAtoms(display, (char **)m_dndMimeTypes, dndTypesCount, 0, m_dndTypes);
47 m_dndTypes[dndTypesCount] = 0;
48
49 m_dndActions = new Atom[8];
50 counter = 0;
51
52 m_dndActions[counter++] = m_dndClass.XdndActionCopy;
53 m_dndActions[counter++] = m_dndClass.XdndActionMove;
54
55#if 0 /* Not supported yet */
56 dndActions[counter++] = dnd->XdndActionLink;
57 dndActions[counter++] = dnd->XdndActionAsk;
58 dndActions[counter++] = dnd->XdndActionPrivate;
59 dndActions[counter++] = dnd->XdndActionList;
60 dndActions[counter++] = dnd->XdndActionDescription;
61#endif
62
63 m_dndActions[counter++] = 0;
64}
65
66void GHOST_DropTargetX11::Uninitialize()
67{
68 xdnd_shut(&m_dndClass);
69
70 delete[] m_dndActions;
71 delete[] m_dndTypes;
72}
73
75 : m_window(window), m_system(system)
76{
77 if (!m_xdndInitialized) {
78 Initialize();
79 m_xdndInitialized = true;
80 GHOST_PRINT("XDND initialized\n");
81 }
82
83 Window wnd = window->getXWindow();
84
85 xdnd_set_dnd_aware(&m_dndClass, wnd, nullptr);
86 xdnd_set_type_list(&m_dndClass, wnd, m_dndTypes);
87
88 m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
89 m_refCounter++;
90}
91
93{
94 m_refCounter--;
95 if (m_refCounter == 0) {
96 Uninitialize();
97 m_xdndInitialized = false;
98 GHOST_PRINT("XDND uninitialized\n");
99 }
100}
101
102char *GHOST_DropTargetX11::FileUrlDecode(const char *fileUrl)
103{
104 if (strncmp(fileUrl, "file://", 7) == 0) {
105 const char *file = fileUrl + 7;
106 return GHOST_URL_decode_alloc(file, strlen(file));
107 }
108
109 return nullptr;
110}
111
112void *GHOST_DropTargetX11::getURIListGhostData(const uchar *dropBuffer, int dropBufferSize)
113{
114 GHOST_TStringArray *strArray = nullptr;
115 int totPaths = 0, curLength = 0;
116
117 /* Count total number of file paths in buffer. */
118 for (int i = 0; i <= dropBufferSize; i++) {
119 if (ELEM(dropBuffer[i], 0, '\n', '\r')) {
120 if (curLength) {
121 totPaths++;
122 curLength = 0;
123 }
124 }
125 else {
126 curLength++;
127 }
128 }
129
130 strArray = (GHOST_TStringArray *)malloc(sizeof(GHOST_TStringArray));
131 strArray->count = 0;
132 strArray->strings = (uint8_t **)malloc(totPaths * sizeof(uint8_t *));
133
134 curLength = 0;
135 for (int i = 0; i <= dropBufferSize; i++) {
136 if (ELEM(dropBuffer[i], 0, '\n', '\r')) {
137 if (curLength) {
138 char *curPath = (char *)malloc(curLength + 1);
139 char *decodedPath;
140
141 strncpy(curPath, (char *)dropBuffer + i - curLength, curLength);
142 curPath[curLength] = 0;
143
144 decodedPath = FileUrlDecode(curPath);
145 if (decodedPath) {
146 strArray->strings[strArray->count] = (uint8_t *)decodedPath;
147 strArray->count++;
148 }
149
150 free(curPath);
151 curLength = 0;
152 }
153 }
154 else {
155 curLength++;
156 }
157 }
158
159 return strArray;
160}
161
162void *GHOST_DropTargetX11::getGhostData(Atom dropType, const uchar *dropBuffer, int dropBufferSize)
163{
164 void *data = nullptr;
165 uchar *tmpBuffer = (uchar *)malloc(dropBufferSize + 1);
166 bool needsFree = true;
167
168 /* Ensure nil-terminator. */
169 memcpy(tmpBuffer, dropBuffer, dropBufferSize);
170 tmpBuffer[dropBufferSize] = 0;
171
172 if (dropType == dndTypeURIList) {
173 m_draggedObjectType = GHOST_kDragnDropTypeFilenames;
174 data = getURIListGhostData(tmpBuffer, dropBufferSize);
175 }
176 else if (dropType == dndTypeURL) {
177 /* need to be tested */
178 char *decodedPath = FileUrlDecode((const char *)tmpBuffer);
179
180 if (decodedPath) {
181 m_draggedObjectType = GHOST_kDragnDropTypeString;
182 data = decodedPath;
183 }
184 }
185 else if (ELEM(dropType, dndTypePlainText, dndTypeOctetStream)) {
186 m_draggedObjectType = GHOST_kDragnDropTypeString;
187 data = tmpBuffer;
188 needsFree = false;
189 }
190 else {
191 m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
192 }
193
194 if (needsFree) {
195 free(tmpBuffer);
196 }
197
198 return data;
199}
200
202{
203 Atom dropType;
204 uchar *dropBuffer;
205 int dropBufferSize, dropX, dropY;
206
207 if (xdnd_get_drop(m_system->getXDisplay(),
208 event,
209 m_dndTypes,
210 m_dndActions,
211 &dropBuffer,
212 &dropBufferSize,
213 &dropType,
214 &dropX,
215 &dropY))
216 {
217 void *data = getGhostData(dropType, dropBuffer, dropBufferSize);
218
219 if (data) {
220 m_system->pushDragDropEvent(
221 GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, dropX, dropY, data);
222 }
223
224 free(dropBuffer);
225
226 m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
227
228 return true;
229 }
230
231 return false;
232}
void BLI_kdtree_nd_ free(KDTree *tree)
unsigned char uchar
#define ARRAY_SIZE(arr)
#define ELEM(...)
#define GHOST_PRINT(x)
#define dndTypeURIList
#define dndTypePlainText
#define dndTypeURL
#define dndTypeOctetStream
char * GHOST_URL_decode_alloc(const char *buf_src, const int buf_src_len)
@ GHOST_kEventDraggingDropDone
@ GHOST_kDragnDropTypeUnknown
@ GHOST_kDragnDropTypeFilenames
@ GHOST_kDragnDropTypeString
bool GHOST_HandleClientMessage(XEvent *event)
void * getGhostData(Atom dropType, const unsigned char *dropBuffer, int dropBufferSize)
GHOST_DropTargetX11(GHOST_WindowX11 *window, GHOST_SystemX11 *system)
Display * getXDisplay()
unsigned char uint8_t
Definition stdint.h:78