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 1002230807689ca1b
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
     1.1 --- a/include/SDL_events.h	Tue Jan 05 01:30:40 2016 -0500
     1.2 +++ b/include/SDL_events.h	Tue Jan 05 01:42:00 2016 -0500
     1.3 @@ -137,6 +137,8 @@
     1.4      /* Drag and drop events */
     1.5      SDL_DROPFILE        = 0x1000, /**< The system requests a file open */
     1.6      SDL_DROPTEXT,                 /**< text/plain drag-and-drop event */
     1.7 +    SDL_DROPBEGIN,                /**< A new set of drops is beginning (NULL filename) */
     1.8 +    SDL_DROPCOMPLETE,             /**< Current set of drops is now complete (NULL filename) */
     1.9  
    1.10      /* Audio hotplug events */
    1.11      SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */
    1.12 @@ -462,9 +464,10 @@
    1.13   */
    1.14  typedef struct SDL_DropEvent
    1.15  {
    1.16 -    Uint32 type;        /**< ::SDL_DROPFILE */
    1.17 +    Uint32 type;        /**< ::SDL_DROPBEGIN or ::SDL_DROPFILE or ::SDL_DROPTEXT or ::SDL_DROPCOMPLETE */
    1.18      Uint32 timestamp;
    1.19 -    char *file;         /**< The file name, which should be freed with SDL_free() */
    1.20 +    char *file;         /**< The file name, which should be freed with SDL_free(), is NULL on begin/complete */
    1.21 +    Uint32 windowID;    /**< The window that was dropped on, if any */
    1.22  } SDL_DropEvent;
    1.23  
    1.24  
     2.1 --- a/src/events/SDL_dropevents.c	Tue Jan 05 01:30:40 2016 -0500
     2.2 +++ b/src/events/SDL_dropevents.c	Tue Jan 05 01:42:00 2016 -0500
     2.3 @@ -26,34 +26,69 @@
     2.4  #include "SDL_events_c.h"
     2.5  #include "SDL_dropevents_c.h"
     2.6  
     2.7 +#include "../video/SDL_sysvideo.h"  /* for SDL_Window internals. */
     2.8 +
     2.9  
    2.10  static int
    2.11 -SDL_SendDrop(const SDL_EventType evtype, const char *data)
    2.12 +SDL_SendDrop(SDL_Window *window, const SDL_EventType evtype, const char *data)
    2.13  {
    2.14 -    int posted;
    2.15 +    static SDL_bool app_is_dropping = SDL_FALSE;
    2.16 +    int posted = 0;
    2.17  
    2.18      /* Post the event, if desired */
    2.19 -    posted = 0;
    2.20      if (SDL_GetEventState(evtype) == SDL_ENABLE) {
    2.21 +        const SDL_bool need_begin = window ? !window->is_dropping : !app_is_dropping;
    2.22          SDL_Event event;
    2.23 +
    2.24 +        if (need_begin) {
    2.25 +            SDL_zero(event);
    2.26 +            event.type = SDL_DROPBEGIN;
    2.27 +            event.drop.windowID = window->id;
    2.28 +            posted = (SDL_PushEvent(&event) > 0);
    2.29 +            if (!posted) {
    2.30 +                return 0;
    2.31 +            }
    2.32 +            if (window) {
    2.33 +                window->is_dropping = SDL_TRUE;
    2.34 +            } else {
    2.35 +                app_is_dropping = SDL_TRUE;
    2.36 +            }
    2.37 +        }
    2.38 +
    2.39          SDL_zero(event);
    2.40          event.type = evtype;
    2.41 -        event.drop.file = SDL_strdup(data);
    2.42 +        event.drop.file = data ? SDL_strdup(data) : NULL;
    2.43 +        event.drop.windowID = window ? window->id : 0;
    2.44          posted = (SDL_PushEvent(&event) > 0);
    2.45 +
    2.46 +        if (posted && (evtype == SDL_DROPCOMPLETE)) {
    2.47 +            if (window) {
    2.48 +                window->is_dropping = SDL_FALSE;
    2.49 +            } else {
    2.50 +                app_is_dropping = SDL_FALSE;
    2.51 +            }
    2.52 +        }
    2.53      }
    2.54      return posted;
    2.55  }
    2.56  
    2.57  int
    2.58 -SDL_SendDropFile(const char *file)
    2.59 +SDL_SendDropFile(SDL_Window *window, const char *file)
    2.60  {
    2.61 -    return SDL_SendDrop(SDL_DROPFILE, file);
    2.62 +    return SDL_SendDrop(window, SDL_DROPFILE, file);
    2.63  }
    2.64  
    2.65  int
    2.66 -SDL_SendDropText(const char *text)
    2.67 +SDL_SendDropText(SDL_Window *window, const char *text)
    2.68  {
    2.69 -    return SDL_SendDrop(SDL_DROPTEXT, text);
    2.70 +    return SDL_SendDrop(window, SDL_DROPTEXT, text);
    2.71  }
    2.72  
    2.73 +int
    2.74 +SDL_SendDropComplete(SDL_Window *window)
    2.75 +{
    2.76 +    return SDL_SendDrop(window, SDL_DROPCOMPLETE, NULL);
    2.77 +}
    2.78 +
    2.79 +
    2.80  /* vi: set ts=4 sw=4 expandtab: */
     3.1 --- a/src/events/SDL_dropevents_c.h	Tue Jan 05 01:30:40 2016 -0500
     3.2 +++ b/src/events/SDL_dropevents_c.h	Tue Jan 05 01:42:00 2016 -0500
     3.3 @@ -23,8 +23,9 @@
     3.4  #ifndef _SDL_dropevents_c_h
     3.5  #define _SDL_dropevents_c_h
     3.6  
     3.7 -extern int SDL_SendDropFile(const char *file);
     3.8 -extern int SDL_SendDropText(const char *text);
     3.9 +extern int SDL_SendDropFile(SDL_Window *window, const char *file);
    3.10 +extern int SDL_SendDropText(SDL_Window *window, const char *text);
    3.11 +extern int SDL_SendDropComplete(SDL_Window *window);
    3.12  
    3.13  #endif /* _SDL_dropevents_c_h */
    3.14  
     4.1 --- a/src/video/SDL_sysvideo.h	Tue Jan 05 01:30:40 2016 -0500
     4.2 +++ b/src/video/SDL_sysvideo.h	Tue Jan 05 01:42:00 2016 -0500
     4.3 @@ -95,6 +95,7 @@
     4.4  
     4.5      SDL_bool is_hiding;
     4.6      SDL_bool is_destroying;
     4.7 +    SDL_bool is_dropping;       /* drag/drop in progress, expecting SDL_SendDropComplete(). */
     4.8  
     4.9      SDL_WindowShaper *shaper;
    4.10  
     5.1 --- a/src/video/cocoa/SDL_cocoaevents.m	Tue Jan 05 01:30:40 2016 -0500
     5.2 +++ b/src/video/cocoa/SDL_cocoaevents.m	Tue Jan 05 01:42:00 2016 -0500
     5.3 @@ -176,7 +176,7 @@
     5.4  
     5.5  - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
     5.6  {
     5.7 -    return (BOOL)SDL_SendDropFile([filename UTF8String]);
     5.8 +    return (BOOL)SDL_SendDropFile(NULL, [filename UTF8String]) && SDL_SendDropComplete(NULL);
     5.9  }
    5.10  @end
    5.11  
     6.1 --- a/src/video/cocoa/SDL_cocoawindow.m	Tue Jan 05 01:30:40 2016 -0500
     6.2 +++ b/src/video/cocoa/SDL_cocoawindow.m	Tue Jan 05 01:42:00 2016 -0500
     6.3 @@ -116,9 +116,12 @@
     6.4  - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
     6.5  { @autoreleasepool
     6.6  {
     6.7 +    SDL_VideoDevice *_this = SDL_GetVideoDevice();
     6.8      NSPasteboard *pasteboard = [sender draggingPasteboard];
     6.9      NSArray *types = [NSArray arrayWithObject:NSFilenamesPboardType];
    6.10      NSString *desiredType = [pasteboard availableTypeFromArray:types];
    6.11 +    SDL_Window *sdlwindow = nil;
    6.12 +
    6.13      if (desiredType == nil) {
    6.14          return NO;  /* can't accept anything that's being dropped here. */
    6.15      }
    6.16 @@ -157,11 +160,22 @@
    6.17              }
    6.18          }
    6.19  
    6.20 -        if (!SDL_SendDropFile([[fileURL path] UTF8String])) {
    6.21 +        /* !!! FIXME: is there a better way to do this? */
    6.22 +        if (_this) {
    6.23 +            for (sdlwindow = _this->windows; sdlwindow; sdlwindow = sdlwindow->next) {
    6.24 +                NSWindow *nswindow = ((SDL_WindowData *) sdlwindow->driverdata)->nswindow;
    6.25 +                if (nswindow == self) {
    6.26 +                    break;
    6.27 +                }
    6.28 +            }
    6.29 +        }
    6.30 +
    6.31 +        if (!SDL_SendDropFile(sdlwindow, [[fileURL path] UTF8String])) {
    6.32              return NO;
    6.33          }
    6.34      }
    6.35  
    6.36 +    SDL_SendDropComplete(sdlwindow);
    6.37      return YES;
    6.38  }}
    6.39  
     7.1 --- a/src/video/windows/SDL_windowsevents.c	Tue Jan 05 01:30:40 2016 -0500
     7.2 +++ b/src/video/windows/SDL_windowsevents.c	Tue Jan 05 01:42:00 2016 -0500
     7.3 @@ -907,12 +907,13 @@
     7.4                  if (buffer) {
     7.5                      if (DragQueryFile(drop, i, buffer, size)) {
     7.6                          char *file = WIN_StringToUTF8(buffer);
     7.7 -                        SDL_SendDropFile(file);
     7.8 +                        SDL_SendDropFile(data->window, file);
     7.9                          SDL_free(file);
    7.10                      }
    7.11                      SDL_stack_free(buffer);
    7.12                  }
    7.13              }
    7.14 +            SDL_SendDropComplete(data->window);
    7.15              DragFinish(drop);
    7.16              return 0;
    7.17          }
     8.1 --- a/src/video/x11/SDL_x11events.c	Tue Jan 05 01:30:40 2016 -0500
     8.2 +++ b/src/video/x11/SDL_x11events.c	Tue Jan 05 01:42:00 2016 -0500
     8.3 @@ -1230,17 +1230,17 @@
     8.4                      char *token = strtok((char *) p.data, "\r\n");
     8.5                      while (token != NULL) {
     8.6                          if (SDL_strcmp("text/plain", name)==0) {
     8.7 -                            SDL_SendDropText(token);
     8.8 +                            SDL_SendDropText(data->window, token);
     8.9                          } else if (SDL_strcmp("text/uri-list", name)==0) {
    8.10                              char *fn = X11_URIToLocal(token);
    8.11                              if (fn) {
    8.12 -                                SDL_SendDropFile(fn);
    8.13 +                                SDL_SendDropFile(data->window, fn);
    8.14                              }
    8.15                          }
    8.16                          token = strtok(NULL, "\r\n");
    8.17                      }
    8.18 +                    SDL_SendDropComplete(data->window);
    8.19                  }
    8.20 -
    8.21                  X11_XFree(p.data);
    8.22  
    8.23                  /* send reply */
     9.1 --- a/test/testdropfile.c	Tue Jan 05 01:30:40 2016 -0500
     9.2 +++ b/test/testdropfile.c	Tue Jan 05 01:42:00 2016 -0500
     9.3 @@ -77,10 +77,14 @@
     9.4          while (SDL_PollEvent(&event)) {
     9.5              SDLTest_CommonEvent(state, &event, &done);
     9.6  
     9.7 -            if ((event.type == SDL_DROPFILE) || (event.type == SDL_DROPTEXT)) {
     9.8 +            if (event.type == SDL_DROPBEGIN) {
     9.9 +                SDL_Log("Drop beginning on window %u", (unsigned int) event.drop.windowID);
    9.10 +            } else if (event.type == SDL_DROPCOMPLETE) {
    9.11 +                SDL_Log("Drop complete on window %u", (unsigned int) event.drop.windowID);
    9.12 +            } else if ((event.type == SDL_DROPFILE) || (event.type == SDL_DROPTEXT)) {
    9.13                  const char *typestr = (event.type == SDL_DROPFILE) ? "File" : "Text";
    9.14                  char *dropped_filedir = event.drop.file;
    9.15 -                SDL_Log("%s dropped on window: %s", typestr, dropped_filedir);
    9.16 +                SDL_Log("%s dropped on window %u: %s", typestr, (unsigned int) event.drop.windowID, dropped_filedir);
    9.17                  SDL_free(dropped_filedir);
    9.18              }
    9.19          }