changeset 362:a0ea7bcac15b macness

Now can load file when someone chooses from Mac Finder "Open with > Sonic Visualiser" - but currently *only* if the app is already running.
author Dan Stowell <dan.stowell@eecs.qmul.ac.uk>
date Mon, 11 Oct 2010 14:16:54 +0100 (2010-10-11)
parents 101f05420cba
children 43205eda54bd
files main/main.cpp
diffstat 1 files changed, 98 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/main/main.cpp	Fri Oct 08 13:31:00 2010 +0100
+++ b/main/main.cpp	Mon Oct 11 14:16:54 2010 +0100
@@ -23,6 +23,9 @@
 #include "widgets/TipDialog.h"
 #include "transform/TransformFactory.h"
 
+#include <ApplicationServices/ApplicationServices.h>
+#include <Carbon/Carbon.h>
+
 #include <QMetaType>
 #include <QApplication>
 #include <QDesktopWidget>
@@ -171,6 +174,7 @@
 */
 
 static QMutex cleanupMutex;
+static MainWindow *gui;
 
 static void
 signalHandler(int /* signal */)
@@ -202,6 +206,94 @@
         if (!success) manager.cancel();
     }
 
+    /** Application-global handler for filepaths passed in, e.g. as command-line arguments or apple events */
+    static void handleFilepathArgument(QString path, QSplashScreen *splash){
+        static bool haveSession = false;
+        static bool haveMainModel = false;
+        static bool havePriorCommandLineModel = false;
+    
+        MainWindow::FileOpenStatus status = MainWindow::FileOpenFailed;
+    
+        if (path.endsWith("sv")) {
+            if (!haveSession) {
+                status = gui->openSessionFile(path);
+                if (status == MainWindow::FileOpenSucceeded) {
+                    haveSession = true;
+                    haveMainModel = true;
+                }
+            } else {
+                std::cerr << "WARNING: Ignoring additional session file argument \"" << path.toStdString() << "\"" << std::endl;
+                status = MainWindow::FileOpenSucceeded;
+            }
+        }
+        if (status != MainWindow::FileOpenSucceeded) {
+            if (!haveMainModel) {
+                status = gui->open(path, MainWindow::ReplaceMainModel);
+                if (status == MainWindow::FileOpenSucceeded) {
+                    haveMainModel = true;
+                }
+            } else {
+                if (haveSession && !havePriorCommandLineModel) {
+                    status = gui->open(path, MainWindow::AskUser);
+                    if (status == MainWindow::FileOpenSucceeded) {
+                        havePriorCommandLineModel = true;
+                    }
+                } else {
+                    status = gui->open(path, MainWindow::CreateAdditionalModel);
+                }
+            }
+        }
+        if (status == MainWindow::FileOpenFailed) {
+            if (splash) splash->hide();
+            QMessageBox::critical
+                (gui, QMessageBox::tr("Failed to open file"),
+                 QMessageBox::tr("File or URL \"%1\" could not be opened").arg(path));
+        } else if (status == MainWindow::FileOpenWrongMode) {
+            if (splash) splash->hide();
+            QMessageBox::critical
+                (gui, QMessageBox::tr("Failed to open file"),
+                 QMessageBox::tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
+        }
+    }
+    
+#ifdef Q_WS_MAC
+    static pascal OSErr HandleOpenDocAE (const AppleEvent * theAppleEvent, AppleEvent * /* reply */, SInt32 /* handlerRefcon */) {
+        AEDescList  docList;
+        FSRef       theFSRef;
+        long        count = 0;
+        OSErr       err;
+     
+        err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
+        err = AECountItems(&docList, &count);
+        if(count == 0){
+            std::cerr << "SV warning: received apple open-documents event with no documents (count==0)" << std::endl;
+            AEDisposeDesc(&docList);
+            return noErr;
+        }
+        // NB we could be passed a list of files - however, SV on Mac currently can only open one at a time, so we simply open the first.
+
+        err = AEGetNthPtr(&docList, 1, typeFSRef, NULL, NULL, &theFSRef, sizeof(theFSRef), NULL);
+
+        // Call routine to open document with current reference.
+        if(err == noErr){
+            char uPath[1024];
+            FSRefMakePath(&theFSRef, (UInt8*)uPath, 1023);
+            std::cerr << "SV received Apple Event request to open " << uPath << std::endl;
+            handleFilepathArgument(uPath, NULL);
+        }
+
+        AEDisposeDesc(&docList);
+        return noErr;
+    }
+    static OSErr InstallMacOSEventHandlers(void)
+    {
+        OSErr err;
+        err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP(HandleOpenDocAE), 0, false);
+        std::cerr << "HandleOpenDocAE installed. " << err << std::endl;
+        return err;
+    }
+#endif // Q_WS_MAC
+
 protected:
     MainWindow *m_mainWindow;
 };
@@ -315,7 +407,7 @@
     qRegisterMetaType<size_t>("size_t");
     qRegisterMetaType<PropertyContainer::PropertyName>("PropertyContainer::PropertyName");
 
-    MainWindow *gui = new MainWindow(audioOutput, oscSupport);
+    gui = new MainWindow(audioOutput, oscSupport);
     application.setMainWindow(gui);
     if (splash) {
         QObject::connect(gui, SIGNAL(hideSplash()), splash, SLOT(hide()));
@@ -340,6 +432,10 @@
     }
     settings.endGroup();
     
+#ifdef Q_WS_MAC
+    application.InstallMacOSEventHandlers();
+#endif // Q_WS_MAC
+    
     gui->show();
 
     // The MainWindow class seems to have trouble dealing with this if
@@ -347,59 +443,14 @@
     // complete.  As a lazy hack, apply it explicitly from here
     gui->preferenceChanged("Property Box Layout");
 
-    bool haveSession = false;
-    bool haveMainModel = false;
-    bool havePriorCommandLineModel = false;
-
     for (QStringList::iterator i = args.begin(); i != args.end(); ++i) {
 
-        MainWindow::FileOpenStatus status = MainWindow::FileOpenFailed;
-
         if (i == args.begin()) continue;
         if (i->startsWith('-')) continue;
 
         QString path = *i;
 
-        if (path.endsWith("sv")) {
-            if (!haveSession) {
-                status = gui->openSessionFile(path);
-                if (status == MainWindow::FileOpenSucceeded) {
-                    haveSession = true;
-                    haveMainModel = true;
-                }
-            } else {
-                std::cerr << "WARNING: Ignoring additional session file argument \"" << path.toStdString() << "\"" << std::endl;
-                status = MainWindow::FileOpenSucceeded;
-            }
-        }
-        if (status != MainWindow::FileOpenSucceeded) {
-            if (!haveMainModel) {
-                status = gui->open(path, MainWindow::ReplaceMainModel);
-                if (status == MainWindow::FileOpenSucceeded) {
-                    haveMainModel = true;
-                }
-            } else {
-                if (haveSession && !havePriorCommandLineModel) {
-                    status = gui->open(path, MainWindow::AskUser);
-                    if (status == MainWindow::FileOpenSucceeded) {
-                        havePriorCommandLineModel = true;
-                    }
-                } else {
-                    status = gui->open(path, MainWindow::CreateAdditionalModel);
-                }
-            }
-        }
-        if (status == MainWindow::FileOpenFailed) {
-            if (splash) splash->hide();
-	    QMessageBox::critical
-                (gui, QMessageBox::tr("Failed to open file"),
-                 QMessageBox::tr("File or URL \"%1\" could not be opened").arg(path));
-        } else if (status == MainWindow::FileOpenWrongMode) {
-            if (splash) splash->hide();
-            QMessageBox::critical
-                (gui, QMessageBox::tr("Failed to open file"),
-                 QMessageBox::tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
-        }
+        SVApplication::handleFilepathArgument(path, splash);
     }
     
 #ifdef HAVE_FFTW3F