Get drag and drop to self working in cocoa backend

This commit is contained in:
Kovid Goyal 2026-02-07 16:42:56 +05:30
parent e186965bda
commit 19f24f2623
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 30 additions and 55 deletions

View file

@ -176,10 +176,6 @@ typedef struct _GLFWwindowNS
int dragMimeCount; // Current count of MIME types (may be reduced by callback)
int dragMimeArraySize; // Original array size for proper cleanup
// Drag source state
char** sourceMimes; // Array of MIME type strings for drag source
int sourceMimeCount; // Number of source MIME types
// Pending drag source data requests (for cleanup on cancellation)
GLFWDragSourceData** pendingDragSourceData;
int pendingDragSourceDataCount;

View file

@ -1618,9 +1618,10 @@ static void freeFilteredDragMimes(_GLFWwindow* window, int old_count, int new_co
// Count total types across all pasteboard items plus 2 for uri-list and text/plain
size_t max_types = 2;
for (NSPasteboardItem* item in pasteboard.pasteboardItems) {
max_types += [item.types count];
}
for (NSPasteboardItem* item in pasteboard.pasteboardItems) max_types += [item.types count];
NSArray *classes = [NSArray arrayWithObject:[NSFilePromiseReceiver class]];
NSArray *receivers = [pasteboard readObjectsForClasses:classes options:@{}];
for (NSFilePromiseReceiver *receiver in receivers) max_types += [receiver.fileTypes count];
// Free any previously cached MIME types
freeDragMimes(window);
@ -1642,25 +1643,30 @@ static void freeFilteredDragMimes(_GLFWwindow* window, int old_count, int new_co
if ([pasteboard canReadObjectForClasses:@[[NSString class]] options:nil]) {
mime_array[mime_count++] = _glfw_strdup("text/plain");
}
#define add_mime(uti) { \
const char* mime = uti_to_mime(uti); \
if (mime && mime[0]) { \
bool duplicate = false; \
for (int i = 0; i < mime_count; i++) { \
if (strcmp(mime_array[i], mime) == 0) { \
duplicate = true; \
break; \
} \
} \
if (!duplicate) mime_array[mime_count++] = _glfw_strdup(mime); \
} \
}
// Get file promise based types
for (NSFilePromiseReceiver *receiver in receivers) {
for (NSString *uti in receiver.fileTypes) {
add_mime(uti);
}
}
// Get additional types from pasteboard items
for (NSPasteboardItem* item in pasteboard.pasteboardItems) {
for (NSPasteboardType type in item.types) {
const char* mime = uti_to_mime(type);
if (mime && mime[0]) {
// Check for duplicates
bool duplicate = false;
for (int i = 0; i < mime_count; i++) {
if (strcmp(mime_array[i], mime) == 0) {
duplicate = true;
break;
}
}
if (!duplicate) {
// Use _glfw_strdup since uti_to_mime returns strings from autoreleased objects
mime_array[mime_count++] = _glfw_strdup(mime);
}
}
for (NSPasteboardType uti in item.types) {
add_mime(uti);
}
}
@ -1788,13 +1794,6 @@ static void freeFilteredDragMimes(_GLFWwindow* window, int old_count, int new_co
cleanup_all_ns_pending_drag_source_data(window);
// Notify the application that the drag source is closed
_glfwInputDragSourceRequest(window, NULL, NULL);
// Clean up source MIME types
for (int i = 0; i < window->ns.sourceMimeCount; i++) {
free(window->ns.sourceMimes[i]);
}
free(window->ns.sourceMimes);
window->ns.sourceMimes = NULL;
window->ns.sourceMimeCount = 0;
}
- (BOOL)hasMarkedText
@ -4011,13 +4010,6 @@ void _glfwCocoaPostEmptyEvent(void) {
void _glfwPlatformCancelDrag(_GLFWwindow* window) {
// Clean up all pending drag source data
cleanup_all_ns_pending_drag_source_data(window);
// Clean up source MIME types
for (int i = 0; i < window->ns.sourceMimeCount; i++) {
free(window->ns.sourceMimes[i]);
}
free(window->ns.sourceMimes);
window->ns.sourceMimes = NULL;
window->ns.sourceMimeCount = 0;
// Notify the application that the drag source is closed
_glfwInputDragSourceRequest(window, NULL, NULL);
}
@ -4027,27 +4019,13 @@ int _glfwPlatformStartDrag(_GLFWwindow* window,
int mime_count,
const GLFWimage* thumbnail,
int operations) {
// Cancel any existing drag operation
_glfwPlatformCancelDrag(window);
// cleanup stored data from previous drag
cleanup_all_ns_pending_drag_source_data(window);
// Store the operations for the dragging source callback
window->ns.dragOperations = operations;
@autoreleasepool {
// Store MIME types for later lookup
window->ns.sourceMimes = calloc(mime_count, sizeof(char*));
window->ns.sourceMimeCount = mime_count;
if (!window->ns.sourceMimes) {
return ENOMEM;
}
for (int i = 0; i < mime_count; i++) {
window->ns.sourceMimes[i] = _glfw_strdup(mime_types[i]);
if (!window->ns.sourceMimes[i]) {
_glfwPlatformCancelDrag(window);
return ENOMEM;
}
}
// Create dragging items array - one NSFilePromiseProvider per MIME type
NSMutableArray<NSDraggingItem*>* dragItems = [[NSMutableArray alloc] init];

View file

@ -735,8 +735,8 @@ get_mime_data(GLFWDropData *drop, const char **mimes, int mime_count, PyObject *
for (int i = 0; i < mime_count; i++) {
if (is_droppable_mime(mimes[i])) {
RAII_PyObject(data, read_drop_data(drop, mimes[i]));
if (data == NULL) return ;
if (PyDict_SetItemString(ans, mimes[i], data) != 0) return ;
if (data == NULL) return;
if (PyDict_SetItemString(ans, mimes[i], data) != 0) return;
}
}
}
@ -748,6 +748,7 @@ drop_callback(GLFWwindow *w, GLFWDropData *drop, bool from_self) {
RAII_PyObject(ans, PyDict_New());
if (from_self) {
if (global_state.drag_source.drag_data) PyDict_Update(ans, global_state.drag_source.drag_data);
else log_error("Got a drop from self but drag_source.drag_data is NULL");
} else get_mime_data(drop, mimes, num_mimes, ans);
RAII_PyObject(exc, PyErr_GetRaisedException());
glfwFinishDrop(drop, GLFW_DRAG_OPERATION_COPY, true);