Added SDL_DROPBEGIN and SDL_DROPCOMPLETE events, plus window IDs for drops.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 05 Jan 2016 01:42:00 -0500
changeset 10022 30807689ca1b
parent 10021 3beca914a2ad
child 10023 d8015905fef6
Added SDL_DROPBEGIN and SDL_DROPCOMPLETE events, plus window IDs for drops. This allows an app to know when a set of drops are coming in a grouping of some sort (for example, a user selected multiple files and dropped them all on the window with a single drag), and when that set is complete. This also adds a window ID to the drop events, so the app can determine to which window a given drop was delivered. For application-level drops (for example, you launched an app by dropping a file on its icon), the window ID will be zero.
include/SDL_events.h
src/events/SDL_dropevents.c
src/events/SDL_dropevents_c.h
src/video/SDL_sysvideo.h
src/video/cocoa/SDL_cocoaevents.m
src/video/cocoa/SDL_cocoawindow.m
src/video/windows/SDL_windowsevents.c
src/video/x11/SDL_x11events.c
test/testdropfile.c
--- a/include/SDL_events.h	Tue Jan 05 01:30:40 2016 -0500
+++ b/include/SDL_events.h	Tue Jan 05 01:42:00 2016 -0500
@@ -137,6 +137,8 @@
     /* Drag and drop events */
     SDL_DROPFILE        = 0x1000, /**< The system requests a file open */
     SDL_DROPTEXT,                 /**< text/plain drag-and-drop event */
+    SDL_DROPBEGIN,                /**< A new set of drops is beginning (NULL filename) */
+    SDL_DROPCOMPLETE,             /**< Current set of drops is now complete (NULL filename) */
 
     /* Audio hotplug events */
     SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */
@@ -462,9 +464,10 @@
  */
 typedef struct SDL_DropEvent
 {
-    Uint32 type;        /**< ::SDL_DROPFILE */
+    Uint32 type;        /**< ::SDL_DROPBEGIN or ::SDL_DROPFILE or ::SDL_DROPTEXT or ::SDL_DROPCOMPLETE */
     Uint32 timestamp;
-    char *file;         /**< The file name, which should be freed with SDL_free() */
+    char *file;         /**< The file name, which should be freed with SDL_free(), is NULL on begin/complete */
+    Uint32 windowID;    /**< The window that was dropped on, if any */
 } SDL_DropEvent;
 
 
--- a/src/events/SDL_dropevents.c	Tue Jan 05 01:30:40 2016 -0500
+++ b/src/events/SDL_dropevents.c	Tue Jan 05 01:42:00 2016 -0500
@@ -26,34 +26,69 @@
 #include "SDL_events_c.h"
 #include "SDL_dropevents_c.h"
 
+#include "../video/SDL_sysvideo.h"  /* for SDL_Window internals. */
+
 
 static int
-SDL_SendDrop(const SDL_EventType evtype, const char *data)
+SDL_SendDrop(SDL_Window *window, const SDL_EventType evtype, const char *data)
 {
-    int posted;
+    static SDL_bool app_is_dropping = SDL_FALSE;
+    int posted = 0;
 
     /* Post the event, if desired */
-    posted = 0;
     if (SDL_GetEventState(evtype) == SDL_ENABLE) {
+        const SDL_bool need_begin = window ? !window->is_dropping : !app_is_dropping;
         SDL_Event event;
+
+        if (need_begin) {
+            SDL_zero(event);
+            event.type = SDL_DROPBEGIN;
+            event.drop.windowID = window->id;
+            posted = (SDL_PushEvent(&event) > 0);
+            if (!posted) {
+                return 0;
+            }
+            if (window) {
+                window->is_dropping = SDL_TRUE;
+            } else {
+                app_is_dropping = SDL_TRUE;
+            }
+        }
+
         SDL_zero(event);
         event.type = evtype;
-        event.drop.file = SDL_strdup(data);
+        event.drop.file = data ? SDL_strdup(data) : NULL;
+        event.drop.windowID = window ? window->id : 0;
         posted = (SDL_PushEvent(&event) > 0);
+
+        if (posted && (evtype == SDL_DROPCOMPLETE)) {
+            if (window) {
+                window->is_dropping = SDL_FALSE;
+            } else {
+                app_is_dropping = SDL_FALSE;
+            }
+        }
     }
     return posted;
 }
 
 int
-SDL_SendDropFile(const char *file)
+SDL_SendDropFile(SDL_Window *window, const char *file)
 {
-    return SDL_SendDrop(SDL_DROPFILE, file);
+    return SDL_SendDrop(window, SDL_DROPFILE, file);
 }
 
 int
-SDL_SendDropText(const char *text)
+SDL_SendDropText(SDL_Window *window, const char *text)
 {
-    return SDL_SendDrop(SDL_DROPTEXT, text);
+    return SDL_SendDrop(window, SDL_DROPTEXT, text);
 }
 
+int
+SDL_SendDropComplete(SDL_Window *window)
+{
+    return SDL_SendDrop(window, SDL_DROPCOMPLETE, NULL);
+}
+
+
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/events/SDL_dropevents_c.h	Tue Jan 05 01:30:40 2016 -0500
+++ b/src/events/SDL_dropevents_c.h	Tue Jan 05 01:42:00 2016 -0500
@@ -23,8 +23,9 @@
 #ifndef _SDL_dropevents_c_h
 #define _SDL_dropevents_c_h
 
-extern int SDL_SendDropFile(const char *file);
-extern int SDL_SendDropText(const char *text);
+extern int SDL_SendDropFile(SDL_Window *window, const char *file);
+extern int SDL_SendDropText(SDL_Window *window, const char *text);
+extern int SDL_SendDropComplete(SDL_Window *window);
 
 #endif /* _SDL_dropevents_c_h */
 
--- a/src/video/SDL_sysvideo.h	Tue Jan 05 01:30:40 2016 -0500
+++ b/src/video/SDL_sysvideo.h	Tue Jan 05 01:42:00 2016 -0500
@@ -95,6 +95,7 @@
 
     SDL_bool is_hiding;
     SDL_bool is_destroying;
+    SDL_bool is_dropping;       /* drag/drop in progress, expecting SDL_SendDropComplete(). */
 
     SDL_WindowShaper *shaper;
 
--- a/src/video/cocoa/SDL_cocoaevents.m	Tue Jan 05 01:30:40 2016 -0500
+++ b/src/video/cocoa/SDL_cocoaevents.m	Tue Jan 05 01:42:00 2016 -0500
@@ -176,7 +176,7 @@
 
 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
 {
-    return (BOOL)SDL_SendDropFile([filename UTF8String]);
+    return (BOOL)SDL_SendDropFile(NULL, [filename UTF8String]) && SDL_SendDropComplete(NULL);
 }
 @end
 
--- a/src/video/cocoa/SDL_cocoawindow.m	Tue Jan 05 01:30:40 2016 -0500
+++ b/src/video/cocoa/SDL_cocoawindow.m	Tue Jan 05 01:42:00 2016 -0500
@@ -116,9 +116,12 @@
 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
 { @autoreleasepool
 {
+    SDL_VideoDevice *_this = SDL_GetVideoDevice();
     NSPasteboard *pasteboard = [sender draggingPasteboard];
     NSArray *types = [NSArray arrayWithObject:NSFilenamesPboardType];
     NSString *desiredType = [pasteboard availableTypeFromArray:types];
+    SDL_Window *sdlwindow = nil;
+
     if (desiredType == nil) {
         return NO;  /* can't accept anything that's being dropped here. */
     }
@@ -157,11 +160,22 @@
             }
         }
 
-        if (!SDL_SendDropFile([[fileURL path] UTF8String])) {
+        /* !!! FIXME: is there a better way to do this? */
+        if (_this) {
+            for (sdlwindow = _this->windows; sdlwindow; sdlwindow = sdlwindow->next) {
+                NSWindow *nswindow = ((SDL_WindowData *) sdlwindow->driverdata)->nswindow;
+                if (nswindow == self) {
+                    break;
+                }
+            }
+        }
+
+        if (!SDL_SendDropFile(sdlwindow, [[fileURL path] UTF8String])) {
             return NO;
         }
     }
 
+    SDL_SendDropComplete(sdlwindow);
     return YES;
 }}
 
--- a/src/video/windows/SDL_windowsevents.c	Tue Jan 05 01:30:40 2016 -0500
+++ b/src/video/windows/SDL_windowsevents.c	Tue Jan 05 01:42:00 2016 -0500
@@ -907,12 +907,13 @@
                 if (buffer) {
                     if (DragQueryFile(drop, i, buffer, size)) {
                         char *file = WIN_StringToUTF8(buffer);
-                        SDL_SendDropFile(file);
+                        SDL_SendDropFile(data->window, file);
                         SDL_free(file);
                     }
                     SDL_stack_free(buffer);
                 }
             }
+            SDL_SendDropComplete(data->window);
             DragFinish(drop);
             return 0;
         }
--- a/src/video/x11/SDL_x11events.c	Tue Jan 05 01:30:40 2016 -0500
+++ b/src/video/x11/SDL_x11events.c	Tue Jan 05 01:42:00 2016 -0500
@@ -1230,17 +1230,17 @@
                     char *token = strtok((char *) p.data, "\r\n");
                     while (token != NULL) {
                         if (SDL_strcmp("text/plain", name)==0) {
-                            SDL_SendDropText(token);
+                            SDL_SendDropText(data->window, token);
                         } else if (SDL_strcmp("text/uri-list", name)==0) {
                             char *fn = X11_URIToLocal(token);
                             if (fn) {
-                                SDL_SendDropFile(fn);
+                                SDL_SendDropFile(data->window, fn);
                             }
                         }
                         token = strtok(NULL, "\r\n");
                     }
+                    SDL_SendDropComplete(data->window);
                 }
-
                 X11_XFree(p.data);
 
                 /* send reply */
--- a/test/testdropfile.c	Tue Jan 05 01:30:40 2016 -0500
+++ b/test/testdropfile.c	Tue Jan 05 01:42:00 2016 -0500
@@ -77,10 +77,14 @@
         while (SDL_PollEvent(&event)) {
             SDLTest_CommonEvent(state, &event, &done);
 
-            if ((event.type == SDL_DROPFILE) || (event.type == SDL_DROPTEXT)) {
+            if (event.type == SDL_DROPBEGIN) {
+                SDL_Log("Drop beginning on window %u", (unsigned int) event.drop.windowID);
+            } else if (event.type == SDL_DROPCOMPLETE) {
+                SDL_Log("Drop complete on window %u", (unsigned int) event.drop.windowID);
+            } else if ((event.type == SDL_DROPFILE) || (event.type == SDL_DROPTEXT)) {
                 const char *typestr = (event.type == SDL_DROPFILE) ? "File" : "Text";
                 char *dropped_filedir = event.drop.file;
-                SDL_Log("%s dropped on window: %s", typestr, dropped_filedir);
+                SDL_Log("%s dropped on window %u: %s", typestr, (unsigned int) event.drop.windowID, dropped_filedir);
                 SDL_free(dropped_filedir);
             }
         }