Drag & drop implementation at GHOST level (only OSX for now)
authorDamien Plisson <damien.plisson@yahoo.fr>
Tue, 10 Nov 2009 12:56:46 +0000 (12:56 +0000)
committerDamien Plisson <damien.plisson@yahoo.fr>
Tue, 10 Nov 2009 12:56:46 +0000 (12:56 +0000)
The dragging sequence is performed in four phases:

- Start sequence (GHOST_kEventDraggingEntered) that tells a drag'n'drop operation has started. Already gives the object data type, and the entering mouse location

- Update mouse position (GHOST_kEventDraggingUpdated) sent upon each mouse move until the drag'n'drop operation stops, to give the updated mouse position.
Useful to highlight a potential destination, and update the status (through GHOST_setAcceptDragOperation) telling if the object can be dropped at the current cursor position.

- Abort drag'n'drop sequence (GHOST_kEventDraggingExited) sent when the user moved the mouse outside the window.

- Send the dropped data (GHOST_kEventDraggingDropDone)

- Outside of the normal sequence, dropped data can be sent (GHOST_kEventDraggingDropOnIcon). This can happen when the user drops an object on the application icon. (Also used in OSX to pass the filename of the document the user doubled-clicked in the finder)

Note that the event handler is responsible for freeing the received data.
And the mouse position is sent directly in blender client coordinates (y=0 at bottom)

The GHOST_setAcceptDragOperation(TRUE) call must be placed before the user drops the object for it to be accepted.

Current handled data types :
- Text string
- Array of filenames (full paths)
- Bitmap image (not implemented yet)

intern/ghost/GHOST_C-api.h
intern/ghost/GHOST_ISystem.h
intern/ghost/GHOST_Types.h
intern/ghost/intern/GHOST_C-api.cpp
intern/ghost/intern/GHOST_EventDragnDrop.h [new file with mode: 0644]
intern/ghost/intern/GHOST_System.cpp
intern/ghost/intern/GHOST_System.h
intern/ghost/intern/GHOST_SystemCocoa.h
intern/ghost/intern/GHOST_SystemCocoa.mm
intern/ghost/intern/GHOST_WindowCocoa.h
intern/ghost/intern/GHOST_WindowCocoa.mm

index bd812177f17d6633a028dc3b21fc36c1e59d6c94..5e434c0eaa09a49da1e4b71ce679ea35ca3894db 100644 (file)
@@ -406,6 +406,17 @@ extern GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
                                                                                   GHOST_TButtonMask mask,
                                                                                   int* isDown);
 
+
+/***************************************************************************************
+ ** Drag'n'drop operations
+ ***************************************************************************************/
+
+/**
+ * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop
+ */
+extern void GHOST_setAcceptDragOperation(GHOST_SystemHandle systemhandle, GHOST_TInt8 canAccept);
+       
+       
 /**
  * Returns the event type.
  * @param eventhandle The handle to the event
index 08794dfd085366299b6d83901f49d14c43a108c2..e56a0dae879df1f2282a15fdbbccbb5067d5fbf8 100644 (file)
@@ -351,6 +351,11 @@ public:
         */
        virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const = 0;
 
+       
+       /***************************************************************************************
+        ** Access to clipboard.
+        ***************************************************************************************/
+       
        /**
         * Returns the selection buffer
         * @return Returns "unsinged char" from X11 XA_CUT_BUFFER0 buffer
@@ -363,6 +368,22 @@ public:
         */
        virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0;
 
+       
+       /***************************************************************************************
+        ** Drag'n'drop operations
+        ***************************************************************************************/
+       
+       /**
+        * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop
+        */
+       virtual void setAcceptDragOperation(bool canAccept) = 0;
+       
+       /**
+        * Returns acceptance of the dropped object
+        * Usually called by the "object dropped" event handling function
+        */
+       virtual bool canAcceptDragOperation() const = 0;
+       
 protected:
        /**
         * Initialize the system.
index e98e58740ada8a723cea9c6d561be4e42b540efa..5c888e218d84287ffc0a08856ea59b3a2a049596 100644 (file)
@@ -167,6 +167,12 @@ typedef enum {
        GHOST_kEventWindowUpdate,
        GHOST_kEventWindowSize,
        GHOST_kEventWindowMove,
+       
+       GHOST_kEventDraggingEntered,
+       GHOST_kEventDraggingUpdated,
+       GHOST_kEventDraggingExited,
+       GHOST_kEventDraggingDropDone,
+       GHOST_kEventDraggingDropOnIcon,
 
        GHOST_kEventTimer,
 
@@ -368,6 +374,30 @@ typedef struct {
 } GHOST_TEventWheelData;
 
 
+typedef enum {
+       GHOST_kDragnDropTypeUnknown =0,
+       GHOST_kDragnDropTypeFilenames, /*Array of strings representing file names (full path) */
+       GHOST_kDragnDropTypeString, /* Unformatted text UTF-8 string */
+       GHOST_kDragnDropTypeBitmap /*Bitmap image data */
+} GHOST_TDragnDropTypes;
+
+typedef struct {
+       /** The x-coordinate of the cursor position. */
+       GHOST_TInt32 x;
+       /** The y-coordinate of the cursor position. */
+       GHOST_TInt32 y;
+       /** The dropped item type */
+       GHOST_TDragnDropTypes dataType;
+       /** The "dropped content" */
+       GHOST_TEventDataPtr data;
+} GHOST_TEventDragnDropData;
+
+typedef struct {
+       int count;
+       GHOST_TUns8 **strings;
+} GHOST_TStringArray;
+
+
 /* original patch used floats, but the driver return ints and uns. We will calibrate in view, no sense on doing conversions twice */
 /* as all USB device controls are likely to use ints, this is also more future proof */
 //typedef struct {
index 0160df552cc10df5f04bf3b841ab383bc2a5d057..76b3d7caf7e5bff01589a35e51c5ca82a0a306ee 100644 (file)
@@ -404,6 +404,13 @@ GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
 }
 
 
+void GHOST_setAcceptDragOperation(GHOST_SystemHandle systemhandle, GHOST_TInt8 canAccept)
+{
+       GHOST_ISystem* system = (GHOST_ISystem*) systemhandle;
+
+       system->setAcceptDragOperation(canAccept);
+}
+
 
 GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle)
 {
diff --git a/intern/ghost/intern/GHOST_EventDragnDrop.h b/intern/ghost/intern/GHOST_EventDragnDrop.h
new file mode 100644 (file)
index 0000000..9731ddf
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * $Id: GHOST_EventDragnDrop.h 13161 2008-01-07 19:13:47Z hos $
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Damien Plisson 11/2009
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _GHOST_EVENT_DRAGNDROP_H_
+#define _GHOST_EVENT_DRAGNDROP_H_
+
+#include "GHOST_Event.h"
+
+/**
+ * Drag & drop event
+ * 
+ * The dragging sequence is performed in four phases:
+ * 
+ * <li> Start sequence (GHOST_kEventDraggingEntered) that tells a drag'n'drop operation has started. Already gives the object data type,
+ * and the entering mouse location
+ *
+ * <li> Update mouse position (GHOST_kEventDraggingUpdated) sent upon each mouse move until the drag'n'drop operation stops, to give the updated mouse position.
+ * Useful to highlight a potential destination, and update the status (through GHOST_setAcceptDragOperation) telling if the object can be dropped at
+ * the current cursor position.
+ *
+ * <li> Abort drag'n'drop sequence (GHOST_kEventDraggingExited) sent when the user moved the mouse outside the window.
+ *
+ * <li> Send the dropped data (GHOST_kEventDraggingDropDone)
+ *
+ * <li> Outside of the normal sequence, dropped data can be sent (GHOST_kEventDraggingDropOnIcon). This can happen when the user drops an object
+ * on the application icon. (Also used in OSX to pass the filename of the document the user doubled-clicked in the finder)
+ *
+ * <br><br>Note that the event handler is responsible for freeing the received data.
+ * <br>And the mouse positions are given in Blender coordinates (y=0 at bottom)
+ *
+ * <br>Currently supported object types :
+ * <li>UTF-8 string
+ * <li>array of strings representing filenames (GHOST_TStringArray)
+ * <li>bitmap image
+ */
+class GHOST_EventDragnDrop : public GHOST_Event
+{
+public:
+       /**
+        * Constructor.
+        * @param time          The time this event was generated.
+        * @param type          The type of this event.
+        * @param dataType      The type of the drop candidate object
+        * @param window        The window where the event occured
+        * @param x                     The x-coordinate of the location the cursor was at at the time of the event.
+        * @param y                     The y-coordinate of the location the cursor was at at the time of the event.
+        * @param data          The "content" dropped in the window
+        */
+       GHOST_EventDragnDrop(GHOST_TUns64 time, GHOST_TEventType type, GHOST_TDragnDropTypes dataType, GHOST_IWindow* window,
+                                                int x, int y, GHOST_TEventDataPtr data)
+               : GHOST_Event(time, type, window)
+       {
+               m_dragnDropEventData.x = x;
+               m_dragnDropEventData.y = y;
+               m_dragnDropEventData.dataType = dataType;
+               m_dragnDropEventData.data = data;
+               m_data = &m_dragnDropEventData;
+       }
+
+protected:
+       /** The x,y-coordinates of the cursor position. */
+       GHOST_TEventDragnDropData m_dragnDropEventData;
+};
+
+#endif // _GHOST_EVENT_DRAGNDROP_H_
+
index 84298d3e3ff42370da5c819fe51f82dedfc8a361..cccee12d6964d69fd3436e6007f2275703e2827b 100644 (file)
@@ -54,6 +54,7 @@
 GHOST_System::GHOST_System()
 : m_displayManager(0), m_timerManager(0), m_windowManager(0), m_eventManager(0), m_ndofManager(0)
 {
+       m_canAcceptDragOperation = false;
 }
 
 
@@ -275,6 +276,15 @@ GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool& isDown
        return success;
 }
 
+void GHOST_System::setAcceptDragOperation(bool canAccept)
+{
+       m_canAcceptDragOperation = canAccept;
+}
+
+bool GHOST_System::canAcceptDragOperation() const
+{
+       return m_canAcceptDragOperation;
+}
 
 GHOST_TSuccess GHOST_System::init()
 {
index 066fe4b93d31aa0ba22a45ca33eb60671bd93709..542553e830e7811680979a267b2080917a6f7085 100644 (file)
@@ -231,6 +231,21 @@ public:
         * @return                      Indication of success.
         */
        virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const;
+       
+       /***************************************************************************************
+        ** Drag'n'drop operations
+        ***************************************************************************************/
+       
+       /**
+        * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop
+        */
+       virtual void setAcceptDragOperation(bool canAccept);
+       
+       /**
+        * Returns acceptance of the dropped object
+        * Usually called by the "object dropped" event handling function
+        */
+       virtual bool canAcceptDragOperation() const;
 
        /***************************************************************************************
         ** Other (internal) functionality.
@@ -332,6 +347,9 @@ protected:
 
     /** The N-degree of freedom device manager */
     GHOST_NDOFManager* m_ndofManager;
+       
+       /** The acceptance of the "drop candidate" of the current drag'n'drop operation */
+       bool m_canAcceptDragOperation;
 
        /** Prints all the events. */
 #ifdef GHOST_DEBUG
index e880f8512679eef42f82bb58e2b967da3a53aced..5ba3a2b373ba55bd3c853523ebe1e52cef10506c 100644 (file)
@@ -194,11 +194,25 @@ public:
 
        /**
      * Handles a window event. Called by GHOST_WindowCocoa window delegate
-     * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
+     * @param eventType The type of window event
+        * @param window The window on which the event occured
      * @return Indication whether the event was handled. 
      */
     GHOST_TSuccess handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window);
        
+       
+       /**
+     * Handles a drag'n'drop destination event. Called by GHOST_WindowCocoa window subclass
+     * @param eventType The type of drag'n'drop event
+        * @param draggedObjectType The type object concerned (currently array of file names, string, TIFF image)
+        * @param mouseX x mouse coordinate (in cocoa base window coordinates)
+        * @param mouseY y mouse coordinate
+        * @param window The window on which the event occured
+     * @return Indication whether the event was handled. 
+     */
+       GHOST_TSuccess handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType,
+                                                                          GHOST_WindowCocoa* window, int mouseX, int mouseY, void* data);
+       
 protected:
        /**
         * Initializes the system.
index 73be363dff189756411e54f2dfcf81cbb2cb504e..c7127e26a4abcce3fc45429450daea975fb34f7a 100644 (file)
@@ -41,6 +41,7 @@
 #include "GHOST_EventCursor.h"
 #include "GHOST_EventWheel.h"
 #include "GHOST_EventNDOF.h"
+#include "GHOST_EventDragnDrop.h"
 
 #include "GHOST_TimerManager.h"
 #include "GHOST_TimerTask.h"
@@ -413,6 +414,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) {
 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
 {
        NSLog(@"\nGet open file event from cocoa : %@",filename);
+       systemCocoa->handleDraggingEvent(GHOST_kEventDraggingDropOnIcon, GHOST_kDragnDropTypeFilenames, nil, 0, 0, [NSArray arrayWithObject:filename]);
        return YES;
 }
 
@@ -880,6 +882,102 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
        return GHOST_kSuccess;
 }
 
+//Note: called from NSWindow subclass
+GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType,
+                                                                  GHOST_WindowCocoa* window, int mouseX, int mouseY, void* data)
+{
+       if (!validWindow(window)) {
+               return GHOST_kFailure;
+       }
+       switch(eventType) 
+       {
+               case GHOST_kEventDraggingEntered:
+                       setAcceptDragOperation(FALSE); //Drag operation needs to be accepted explicitely by the event manager
+               case GHOST_kEventDraggingUpdated:
+               case GHOST_kEventDraggingExited:
+                       pushEvent(new GHOST_EventDragnDrop(getMilliSeconds(),GHOST_kEventDraggingEntered,draggedObjectType,window,mouseX,mouseY,NULL));
+                       break;
+                       
+               case GHOST_kEventDraggingDropDone:
+               case GHOST_kEventDraggingDropOnIcon:
+               {
+                       GHOST_TUns8 * temp_buff;
+                       GHOST_TStringArray *strArray;
+                       NSArray *droppedArray;
+                       size_t pastedTextSize;  
+                       NSString *droppedStr;
+                       GHOST_TEventDataPtr eventData;
+                       int i;
+
+                       if (!data) return GHOST_kFailure;
+                       
+                       switch (draggedObjectType) {
+                               case GHOST_kDragnDropTypeBitmap:
+                                       //TODO: implement bitmap conversion to a blender friendly format
+                                       break;
+                               case GHOST_kDragnDropTypeFilenames:
+                                       droppedArray = (NSArray*)data;
+                                       
+                                       strArray = (GHOST_TStringArray*)malloc(sizeof(GHOST_TStringArray));
+                                       if (!strArray) return GHOST_kFailure;
+                                       
+                                       strArray->count = [droppedArray count];
+                                       if (strArray->count == 0) return GHOST_kFailure;
+                                       
+                                       strArray->strings = (GHOST_TUns8**) malloc(strArray->count*sizeof(GHOST_TUns8*));
+                                       
+                                       for (i=0;i<strArray->count;i++)
+                                       {
+                                               droppedStr = [droppedArray objectAtIndex:i];
+                                               
+                                               pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+                                               temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); 
+                                       
+                                               if (!temp_buff) {
+                                                       strArray->count = i;
+                                                       break;
+                                               }
+                                       
+                                               strncpy((char*)temp_buff, [droppedStr UTF8String], pastedTextSize);
+                                               temp_buff[pastedTextSize] = '\0';
+                                               
+                                               strArray->strings[i] = temp_buff;
+                                       }
+
+                                       eventData = (GHOST_TEventDataPtr) strArray;     
+                                       break;
+                                       
+                               case GHOST_kDragnDropTypeString:
+                                       droppedStr = (NSString*)data;
+                                       pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+                                       
+                                       temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); 
+                                       
+                                       if (temp_buff == NULL) {
+                                               return GHOST_kFailure;
+                                       }
+                                       
+                                       strncpy((char*)temp_buff, [droppedStr UTF8String], pastedTextSize);
+                                       
+                                       temp_buff[pastedTextSize] = '\0';
+                                       
+                                       eventData = (GHOST_TEventDataPtr) temp_buff;
+                                       break;
+                                       
+                               default:
+                                       return GHOST_kFailure;
+                                       break;
+                       }
+                       pushEvent(new GHOST_EventDragnDrop(getMilliSeconds(),GHOST_kEventDraggingEntered,draggedObjectType,window,mouseX,mouseY,eventData));
+               }
+                       break;
+               default:
+                       return GHOST_kFailure;
+       }
+       return GHOST_kSuccess;
+}
+
+
 GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest()
 {
        GHOST_Window* window = (GHOST_Window*)m_windowManager->getActiveWindow();
index e3479ada5d69f8c4829e12b09668fa588f66ec2b..e59d9c173330ce69603809fbace61166b998a07d 100644 (file)
@@ -40,6 +40,8 @@
 #include "GHOST_Window.h"
 #include "STR_String.h"
 
+@class CocoaWindow;
+
 class GHOST_SystemCocoa;
 
 /**
@@ -264,7 +266,7 @@ protected:
        virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY);
     
        /** The window containing the OpenGL view */
-    NSWindow *m_window;
+    CocoaWindow *m_window;
        
        /** The openGL view */
        NSOpenGLView *m_openGLView; 
index 6d6829f392534ee20822e9dcaef13e3efe0f67db..459a4a54ee31fe536d2fa32e65be1a22e59f6bbf 100644 (file)
@@ -124,16 +124,86 @@ extern "C" {
 //We need to subclass it to tell that even borderless (fullscreen), it can become key (receive user events)
 @interface CocoaWindow: NSWindow
 {
-
+       GHOST_SystemCocoa *systemCocoa;
+       GHOST_WindowCocoa *associatedWindow;
+       GHOST_TDragnDropTypes m_draggedObjectType;
 }
+- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa;
 @end
 @implementation CocoaWindow
+- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
+{
+       systemCocoa = sysCocoa;
+       associatedWindow = winCocoa;
+}
 
 -(BOOL)canBecomeKeyWindow
 {
        return YES;
 }
 
+//The drag'n'drop dragging destination methods
+- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender
+{
+       NSPoint mouseLocation = [sender draggingLocation];
+       NSPasteboard *draggingPBoard = [sender draggingPasteboard];
+       
+       if ([[draggingPBoard types] containsObject:NSTIFFPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeBitmap;
+       else if ([[draggingPBoard types] containsObject:NSFilenamesPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeFilenames;
+       else if ([[draggingPBoard types] containsObject:NSStringPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeString;
+       else return NSDragOperationNone;
+       
+       systemCocoa->handleDraggingEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil);
+       return NSDragOperationCopy;
+}
+
+
+- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
+{
+       NSPoint mouseLocation = [sender draggingLocation];
+       
+       systemCocoa->handleDraggingEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil);
+       return NSDragOperationCopy;
+}
+
+- (void)draggingExited:(id < NSDraggingInfo >)sender
+{
+       systemCocoa->handleDraggingEvent(GHOST_kEventDraggingExited, m_draggedObjectType, associatedWindow, 0, 0, nil);
+       m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
+}
+
+- (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender
+{
+       if (systemCocoa->canAcceptDragOperation())
+               return YES;
+       else
+               return NO;
+}
+
+- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender
+{
+       NSPoint mouseLocation = [sender draggingLocation];
+       NSPasteboard *draggingPBoard = [sender draggingPasteboard];
+       id data;
+       
+       switch (m_draggedObjectType) {
+               case GHOST_kDragnDropTypeBitmap:
+                       data = [draggingPBoard dataForType:NSTIFFPboardType];
+                       break;
+               case GHOST_kDragnDropTypeFilenames:
+                       data = [draggingPBoard propertyListForType:NSFilenamesPboardType];
+                       break;
+               case GHOST_kDragnDropTypeString:
+                       data = [draggingPBoard stringForType:@"public.utf8-plain-text"];
+                       break;
+               default:
+                       return NO;
+                       break;
+       }
+       systemCocoa->handleDraggingEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, (void*)data);
+       return YES;
+}
+
 @end
 
 
@@ -207,6 +277,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
                return;
        }
        
+       [m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
+       
        //Forbid to resize the window below the blender defined minimum one
        minSize.width = 320;
        minSize.height = 240;
@@ -259,6 +331,9 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
        
        [m_window setAcceptsMouseMovedEvents:YES];
        
+       [m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
+                                                                                 NSStringPboardType, NSTIFFPboardType, nil]];
+                                                                                 
        if (state == GHOST_kWindowStateFullScreen)
                setState(GHOST_kWindowStateFullScreen);