Cocoa : implement opening .blend file by double-clicking on it in OSX Finder

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
This commit is contained in:
Damien Plisson 2010-02-01 09:11:18 +00:00
parent c3e96bf0fc
commit 0e6b88f993
5 changed files with 125 additions and 23 deletions

@ -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,

@ -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;

@ -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_

@ -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;

@ -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 */