Blender V5.0
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
8
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::xdnd_initialized_ = false;
20DndClass GHOST_DropTargetX11::dnd_class_;
21Atom *GHOST_DropTargetX11::dnd_types_ = nullptr;
22Atom *GHOST_DropTargetX11::dnd_actions_ = nullptr;
23const char *GHOST_DropTargetX11::dnd_mime_types_[] = {
24 "url/url", "text/uri-list", "text/plain", "application/octet-stream"};
25int GHOST_DropTargetX11::ref_counter_ = 0;
26
27#define dndTypeURLID 0
28#define dndTypeURIListID 1
29#define dndTypePlainTextID 2
30#define dndTypeOctetStreamID 3
31
32#define dndTypeURL dnd_types_[dndTypeURLID]
33#define dndTypeURIList dnd_types_[dndTypeURIListID]
34#define dndTypePlainText dnd_types_[dndTypePlainTextID]
35#define dndTypeOctetStream dnd_types_[dndTypeOctetStreamID]
36
37void GHOST_DropTargetX11::Initialize()
38{
39 Display *display = system_->getXDisplay();
40 int dndTypesCount = ARRAY_SIZE(dnd_mime_types_);
41 int counter;
42
43 xdnd_init(&dnd_class_, display);
44
45 dnd_types_ = new Atom[dndTypesCount + 1];
46 XInternAtoms(display, (char **)dnd_mime_types_, dndTypesCount, 0, dnd_types_);
47 dnd_types_[dndTypesCount] = 0;
48
49 dnd_actions_ = new Atom[8];
50 counter = 0;
51
52 dnd_actions_[counter++] = dnd_class_.XdndActionCopy;
53 dnd_actions_[counter++] = dnd_class_.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 dnd_actions_[counter++] = 0;
64}
65
66void GHOST_DropTargetX11::Uninitialize()
67{
68 xdnd_shut(&dnd_class_);
69
70 delete[] dnd_actions_;
71 delete[] dnd_types_;
72}
73
75 : window_(window), system_(system)
76{
77 if (!xdnd_initialized_) {
78 Initialize();
79 xdnd_initialized_ = true;
80 GHOST_PRINT("XDND initialized\n");
81 }
82
83 Window wnd = window->getXWindow();
84
85 xdnd_set_dnd_aware(&dnd_class_, wnd, nullptr);
86 xdnd_set_type_list(&dnd_class_, wnd, dnd_types_);
87
88 dragged_object_type_ = GHOST_kDragnDropTypeUnknown;
89 ref_counter_++;
90}
91
93{
94 ref_counter_--;
95 if (ref_counter_ == 0) {
96 Uninitialize();
97 xdnd_initialized_ = 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 dragged_object_type_ = 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 dragged_object_type_ = GHOST_kDragnDropTypeString;
182 data = decodedPath;
183 }
184 }
185 else if (ELEM(dropType, dndTypePlainText, dndTypeOctetStream)) {
186 dragged_object_type_ = GHOST_kDragnDropTypeString;
187 data = tmpBuffer;
188 needsFree = false;
189 }
190 else {
191 dragged_object_type_ = 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(system_->getXDisplay(),
208 event,
209 dnd_types_,
210 dnd_actions_,
211 &dropBuffer,
212 &dropBufferSize,
213 &dropType,
214 &dropX,
215 &dropY))
216 {
217 void *data = getGhostData(dropType, dropBuffer, dropBufferSize);
218
219 if (data) {
220 system_->pushDragDropEvent(
221 GHOST_kEventDraggingDropDone, dragged_object_type_, window_, dropX, dropY, data);
222 }
223
224 free(dropBuffer);
225
226 dragged_object_type_ = 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 Window
#define Display
#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
BMesh const char void * data
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()
i
Definition text_draw.cc:230