Reputation: 1620
I've googled a lot, but still unable to find nice solution :/
So, i'm porting one complicated Qt5 application (client of some network service) to Mac OS X (10.7.0 "Lion" and higher).
I need to handle custom file like *.xyz
and custom URL scheme like xyz://
.
Okay, Qt5 has the QFileOpenEvent
class to handle OS X appropriate event.
BUT: this event arrives only after the application event loop starts (obviously)!
And i need to "catch" and handle OS X' file open event BEFORE main
starts, because the program logic was designed to take care of the command line argument handling only.
The simplified main
function code:
int main(int argc, char[]* argv)
{
QApplication app( argc, argv );
QStringList arguments = app.arguments();
if( arguments.count() == argc ) arguments.removeFirst();
Logic appLogic( NULL, &app );
app.installMessageHandler( &appLogic );
// The problem:
// **This function will always called earlier than the any event**
if( ! appLogic.start( arguments ) ) return 0;
// Start processing of events
// Only after this call Logic class get the desired event
return app.exec();
}
Is there a way to get an OS X' file opening event before the C++ main
function starts, or to get "my" file/url in the argv
parameter?
Maybe, some Objective-C
black magic does the job?
NOTE: start
does many complicated - and asynchronous - things. Event arrives during it's execution, so it's hard to handle it when the async stuff is already working. So looks like i just need to prevent start
execution, if the event will arrive.
If the application is already opened, there is no problem.
Upvotes: 7
Views: 1590
Reputation: 1620
I've found one, propably weird, solution - use Qt' event system.
int main(int argc, char[]* argv)
{
QApplication app( argc, argv );
QStringList arguments = app.arguments();
if( arguments.count() == argc ) arguments.removeFirst();
Logic appLogic( NULL, &app );
#ifdef Q_OS_MAC
app.installMessageHandler( &appLogic );
// Here we should alreasy get FileOpenEvent, if it occurs
// NOTE: without this FileOpenEvent will arrive LATER
// than the DryRunEvent!
app.processEvents();
// If there is no file open event in the queue,
// we should just open the blank program window
// NOTE: Qt takes ownership of this event object,
// so you should not delete it manually
DryRunEvent* runEv = new DryRunEvent( p );
a.postEvent( &l, runEv, Qt::LowEventPriority );
#endif
...
#ifndef Q_OS_MAC
if( ! appLogic.start( arguments ) ) return 0;
#endif
return app.exec();
}
Custom event header:
class BaseEvent : public QEvent
{
public:
BaseEvent( QEvent::Type& eType ) : QEvent( getEventType( eType ) )
{
}
~BaseEvent() {}
QEvent::Type getEventType( QEvent::Type& eType )
{
if( eType == QEvent::None )
{
eType = static_cast<QEvent::Type>( QEvent::registerEventType() );
}
return eType;
}
};
class DryRunEvent : public BaseEvent
{
QStringList m_params;
public:
DryRunEvent( const Parameters& params ) :
BaseEvent( eventType ), m_params( params )
{
}
~DryRunEvent(){}
QStringList GetCmdLineParams() const { return m_params; }
public:
static QEvent::Type eventType;
};
Custom event source:
QEvent::Type ViewerDryRunEvent::eventType = QEvent::None;
Logic class header:
class Logic : public QObject
{
Q_OBJECT
Q_DISABLE_COPY( Logic )
public:
explicit Logic(QObject *parent, QApplication* application);
virtual ~Logic();
public slots:
bool Start( QStringList parameters );
void ReceiveParameters( QStringList parameters );
void Stop();
#ifdef Q_OS_MAC
bool Logic::WasStarted() const
{
... Determine wether logic was started or not ...
}
#endif
private:
#ifdef OS_MACOSX
// Virtual overrided functions
bool eventFilter( QObject* obj, QEvent* event )
{
if( event->type() == QEvent::FileOpen )
{
QFileOpenEvent* fileEvent = static_cast< QFileOpenEvent* >(event);
Q_ASSERT( fileEvent != NULL );
QString uri;
if( fileEvent->file().isEmpty() == false )
{
uri = fileEvent->file();
}
else if( fileEvent->url().isEmpty() == false )
{
uri = fileEvent->url().toString();
}
if( uri.isEmpty() == false )
{
if( WasStarted() ) ReceiveParameters( uri );
else Start( uri );
}
return false;
}
else if( event->type() == DryRunEvent::eventType )
{
DryRunEvent* myEvent = static_cast< DryRunEvent* >( event );
Q_ASSERT( myEvent != NULL );
QStringList cmdLineParams = myEvent->GetCmdLineParams();
Q_ASSERT( !WasStarted() );
if( WasStarted() ) return false;
if( !Start( cmdLineParams ) ) m_application->exit( 0 );
return false;
}
// Standard event processing
return QObject::eventFilter( obj, event );
}
#endif
};
I hope someone find this stuff useful :)
Upvotes: 7