Cocoa : implement opening .blend file by double-clicking on it in OSX Finder
authorDamien Plisson <damien.plisson@yahoo.fr>
Mon, 1 Feb 2010 09:11:18 +0000 (09:11 +0000)
committerDamien Plisson <damien.plisson@yahoo.fr>
Mon, 1 Feb 2010 09:11:18 +0000 (09:11 +0000)
When the user double-clicks on a document file in the Finder, OSX doesn't simply give the filename as a command-line argument when calling Blender, as it is done in other OSes.
Instead, it launches the app if needed, and then sends an "openFile" event.

The user can also open a document file by dropping its icon on the app dock icon. But as this is not real Drag'n'drop, I've renamed the Ghost event to a less confusing "GHOST_kEventOpenMainFile" name.

DND Ghost wiki page updated : http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DragnDrop

intern/ghost/GHOST_Types.h
intern/ghost/intern/GHOST_EventPrinter.cpp
intern/ghost/intern/GHOST_EventString.h [new file with mode: 0644]
intern/ghost/intern/GHOST_SystemCocoa.mm
source/blender/windowmanager/intern/wm_window.c

index 9bb8def00d0635ccf68a228e67dfe817f65532d0..ff60aaf9c033e950e3508a1408e27a7e86a29864 100644 (file)
@@ -173,7 +173,8 @@ typedef enum {
        GHOST_kEventDraggingUpdated,
        GHOST_kEventDraggingExited,
        GHOST_kEventDraggingDropDone,
-       GHOST_kEventDraggingDropOnIcon,
+       
+       GHOST_kEventOpenMainFile, // Needed for Cocoa to open double-clicked .blend file at startup
 
        GHOST_kEventTimer,
 
index 91b554744410d97d1e7f152a4ee6fce98681185f..81dafb74333a8274824f058ba4066440bffcdb6b 100644 (file)
@@ -148,26 +148,14 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent* event)
                }
                break;
 
-       case GHOST_kEventDraggingDropOnIcon:
+       case GHOST_kEventOpenMainFile:
                {
-                       GHOST_TEventDragnDropData* dragnDropData = (GHOST_TEventDragnDropData*)((GHOST_IEvent*)event)->getData();
-                       std::cout << "GHOST_kEventDraggingDropOnIcon, dragged object type : " << dragnDropData->dataType;
-                       switch (dragnDropData->dataType) {
-                               case GHOST_kDragnDropTypeString:
-                                       std::cout << " string received = " << (char*)dragnDropData->data;
-                                       break;
-                               case GHOST_kDragnDropTypeFilenames:
-                               {
-                                       GHOST_TStringArray *strArray = (GHOST_TStringArray*)dragnDropData->data;
-                                       int i;
-                                       std::cout << "\nReceived " << strArray->count << " filenames";
-                                       for (i=0;i<strArray->count;i++)
-                                               std::cout << " Filename #" << i << ": " << strArray->strings[i];
-                               }
-                                       break;
-                               default:
-                                       break;
-                       }
+                       GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
+                       
+                       if (eventData)
+                               std::cout << "GHOST_kEventOpenMainFile for path : " << (char*)eventData;
+                       else
+                               std::cout << "GHOST_kEventOpenMainFile with no path specified!!";
                }
                break;
                        
diff --git a/intern/ghost/intern/GHOST_EventString.h b/intern/ghost/intern/GHOST_EventString.h
new file mode 100644 (file)
index 0000000..812a413
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * $Id: GHOST_EventString.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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+/**
+ * @file       GHOST_EventString.h
+ * Declaration of GHOST_EventString class.
+ */
+
+#ifndef _GHOST_EVENTSTRING_H_
+#define _GHOST_EVENTSTRING_H_
+
+#include "GHOST_Event.h"
+
+
+/**
+ * Generic class for events with string data
+ * @author     Damien Plisson
+ * @date       Feb 1, 2010
+ */
+class GHOST_EventString : public GHOST_Event
+{
+public:
+       /**
+        * Constructor.
+        * @param msec  The time this event was generated.
+        * @param type  The type of this event.
+        * @param window The generating window (or NULL if system event).
+        * @param data_ptr Pointer to the (unformatted) data associated with the event
+        */
+       GHOST_EventString(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TEventDataPtr data_ptr)
+               : GHOST_Event(msec, type, window)       {
+                       m_data = data_ptr;
+       }
+
+       ~GHOST_EventString()
+       {
+               if (m_data) free(m_data);
+       }
+};
+
+#endif // _GHOST_EVENTSTRING_H_
+
index 23f95f95df44d68ac1802763f366909f092d7859..440425757c6e6d00ed2a3a38be13c3257c59e4d9 100644 (file)
@@ -43,6 +43,7 @@
 #include "GHOST_EventNDOF.h"
 #include "GHOST_EventTrackpad.h"
 #include "GHOST_EventDragnDrop.h"
+#include "GHOST_EventString.h"
 
 #include "GHOST_TimerManager.h"
 #include "GHOST_TimerTask.h"
@@ -1025,7 +1026,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
 GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType,
                                                                   GHOST_WindowCocoa* window, int mouseX, int mouseY, void* data)
 {
-       if (!validWindow(window) && (eventType != GHOST_kEventDraggingDropOnIcon)) {
+       if (!validWindow(window)) {
                return GHOST_kFailure;
        }
        switch(eventType) 
@@ -1037,7 +1038,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
                        break;
                        
                case GHOST_kEventDraggingDropDone:
-               case GHOST_kEventDraggingDropOnIcon:
                {
                        GHOST_TUns8 * temp_buff;
                        GHOST_TStringArray *strArray;
@@ -1158,7 +1158,18 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
        NSString *filepath = (NSString*)filepathStr;
        int confirmOpen = NSAlertAlternateReturn;
        NSArray *windowsList;
+       char * temp_buff;
+       size_t filenameTextSize;        
+       GHOST_Window* window= (GHOST_Window*)m_windowManager->getActiveWindow();
+       
+       if (!window) {
+               return NO;
+       }       
        
+       //Discard event if we are in cursor grab sequence, it'll lead to "stuck cursor" situation if the alert panel is raised
+       if (window && (window->getCursorGrabMode() != GHOST_kGrabDisable) && (window->getCursorGrabMode() != GHOST_kGrabNormal))
+               return GHOST_kExitCancel;
+
        //Check open windows if some changes are not saved
        if (m_windowManager->getAnyModifiedState())
        {
@@ -1175,7 +1186,20 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
 
        if (confirmOpen == NSAlertAlternateReturn)
        {
-               handleDraggingEvent(GHOST_kEventDraggingDropOnIcon,GHOST_kDragnDropTypeFilenames,NULL,0,0, [NSArray arrayWithObject:filepath]);
+               filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding];
+               
+               temp_buff = (char*) malloc(filenameTextSize+1); 
+               
+               if (temp_buff == NULL) {
+                       return GHOST_kFailure;
+               }
+               
+               strncpy(temp_buff, [filepath cStringUsingEncoding:NSISOLatin1StringEncoding], filenameTextSize);
+               
+               temp_buff[filenameTextSize] = '\0';
+
+               pushEvent(new GHOST_EventString(getMilliSeconds(),GHOST_kEventOpenMainFile,window,(GHOST_TEventDataPtr) temp_buff));
+
                return YES;
        }
        else return NO;
index ed593cb8dcd0f9a7e1702a757eb86922c10803e3..71efdab1f5929ed4ab7f5d3034c81104fb2b9c15 100644 (file)
@@ -34,6 +34,7 @@
 #include "DNA_listBase.h"      
 #include "DNA_screen_types.h"
 #include "DNA_windowmanager_types.h"
+#include "RNA_access.h"
 
 #include "MEM_guardedalloc.h"
 
@@ -714,6 +715,28 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private)
                                }
                                break;
                        }
+                               
+                       case GHOST_kEventOpenMainFile:
+                       {
+                               PointerRNA props_ptr;
+                               wmWindow *oldWindow;
+                               char *path = GHOST_GetEventData(evt);
+                               
+                               if (path) {
+                                       /* operator needs a valid window in context, ensures
+                                        it is correctly set */
+                                       oldWindow = CTX_wm_window(C);
+                                       CTX_wm_window_set(C, win);
+                                       
+                                       WM_operator_properties_create(&props_ptr, "WM_OT_open_mainfile");
+                                       RNA_string_set(&props_ptr, "path", path);
+                                       WM_operator_name_call(C, "WM_OT_open_mainfile", WM_OP_EXEC_DEFAULT, &props_ptr);
+                                       WM_operator_properties_free(&props_ptr);
+                                       
+                                       CTX_wm_window_set(C, oldWindow);
+                               }
+                               break;
+                       }
                        case GHOST_kEventDraggingDropDone:
                        {
                                wmEvent event= *(win->eventstate);      /* copy last state, like mouse coords */