Replace arg parsing function with Qt built ins

This automatically provides version and help functions, and offloads the
arg parsing to a third party lib.
This commit is contained in:
Vasily
2019-03-10 23:12:26 +01:00
committed by username223
parent 5d2901be33
commit 45bb199a0d
2 changed files with 176 additions and 124 deletions
+27 -39
View File
@@ -6,52 +6,39 @@ int main( int argc, char* argv[] )
{ {
setUpLogging( argc, argv ); setUpLogging( argc, argv );
const bool desktopMode = argument::CheckCommandLineArgument( // QCoreApplication (QApplication inherits it.) can parse the args from
argc, argv, argument::kDesktopMode ); // argc and argv. We don't use this since it's relatively slow and we
const bool noSound // need the args before the main Qt stuff happens. If the arg parsing
= argument::CheckCommandLineArgument( argc, argv, argument::kNoSound ); // needs of the program grow it could be useful to utilize the Qt arg
const bool noManifest = argument::CheckCommandLineArgument( // parsing.
argc, argv, argument::kNoManifest ); MyQApplication mainEventLoop( argc, argv );
const bool installManifest = argument::CheckCommandLineArgument( mainEventLoop.setOrganizationName(
argc, argv, argument::kInstallManifest ); advsettings::OverlayController::applicationOrganizationName );
const bool removeManifest = argument::CheckCommandLineArgument( mainEventLoop.setApplicationName(
argc, argv, argument::kRemoveManifest ); advsettings::OverlayController::applicationName );
mainEventLoop.setApplicationDisplayName(
advsettings::OverlayController::applicationDisplayName );
mainEventLoop.setApplicationVersion(
advsettings::OverlayController::applicationVersionString );
// If a command line arg is set, make sure the logs reflect that. qInstallMessageHandler( mainQtMessageHandler );
LOG_IF( desktopMode, INFO ) << "Desktop mode enabled.";
LOG_IF( noSound, INFO ) << "Sound effects disabled."; const auto commandLineArgs
LOG_IF( noManifest, INFO ) << "vrmanifest disabled."; = argument::returnCommandLineParser( mainEventLoop );
LOG_IF( installManifest, INFO ) << "Install manifest enabled.";
LOG_IF( removeManifest, INFO ) << "Remove manifest enabled.";
// It is important that either install_manifest or remove_manifest are true, // It is important that either install_manifest or remove_manifest are true,
// otherwise the handleManifests function will not behave properly. // otherwise the handleManifests function will not behave properly.
if ( installManifest || removeManifest ) if ( commandLineArgs.forceInstallManifest
|| commandLineArgs.forceRemoveManifest )
{ {
// The function does not return, it exits inside the function // The function does not return, it exits inside the function
// with an appropriate exit code. // with an appropriate exit code.
manifest::handleManifests( installManifest, removeManifest ); manifest::handleManifests( commandLineArgs.forceInstallManifest,
commandLineArgs.forceRemoveManifest );
} }
try try
{ {
// QCoreApplication (QApplication inherits it.) can parse the args from
// argc and argv. We don't use this since it's relatively slow and we
// need the args before the main Qt stuff happens. If the arg parsing
// needs of the program grow it could be useful to utilize the Qt arg
// parsing.
MyQApplication mainEventLoop( argc, argv );
mainEventLoop.setOrganizationName(
advsettings::OverlayController::applicationOrganizationName );
mainEventLoop.setApplicationName(
advsettings::OverlayController::applicationName );
mainEventLoop.setApplicationDisplayName(
advsettings::OverlayController::applicationDisplayName );
mainEventLoop.setApplicationVersion(
advsettings::OverlayController::applicationVersionString );
qInstallMessageHandler( mainQtMessageHandler );
// QSettings contains a platform independant way of storing settings in // QSettings contains a platform independant way of storing settings in
// an .ini file. // an .ini file.
QSettings appSettings( QSettings::IniFormat, QSettings appSettings( QSettings::IniFormat,
@@ -67,8 +54,9 @@ int main( int argc, char* argv[] )
// The OverlayController handles the majority of the application specfic // The OverlayController handles the majority of the application specfic
// things. It contains all the other tabs. // things. It contains all the other tabs.
advsettings::OverlayController controller( advsettings::OverlayController controller( commandLineArgs.desktopMode,
desktopMode, noSound, qmlEngine ); commandLineArgs.forceNoSound,
qmlEngine );
QString path = QStandardPaths::locate( QString path = QStandardPaths::locate(
QStandardPaths::AppDataLocation, QStandardPaths::AppDataLocation,
@@ -88,7 +76,7 @@ int main( int argc, char* argv[] )
advsettings::OverlayController::applicationKey ); advsettings::OverlayController::applicationKey );
// Attempts to install the application manifest on all "regular" starts. // Attempts to install the application manifest on all "regular" starts.
if ( !desktopMode && !noManifest ) if ( !commandLineArgs.desktopMode && !commandLineArgs.forceNoManifest )
{ {
try try
{ {
@@ -104,7 +92,7 @@ int main( int argc, char* argv[] )
} }
// Creates an identical settings menu on the desktop as well as in VR. // Creates an identical settings menu on the desktop as well as in VR.
if ( desktopMode ) if ( commandLineArgs.desktopMode )
{ {
auto m_pWindow = new QQuickWindow(); auto m_pWindow = new QQuickWindow();
qobject_cast<QQuickItem*>( quickObj ) qobject_cast<QQuickItem*>( quickObj )
+149 -85
View File
@@ -18,33 +18,163 @@ enum ReturnErrorCode
OPENVR_INIT_ERROR = -2, OPENVR_INIT_ERROR = -2,
}; };
namespace argument struct CommandLineOptions
{ {
// Checks whether a specific string was passed as a launch argument. const bool desktopMode = false;
bool CheckCommandLineArgument( int argc, const bool forceNoSound = false;
char* argv[], const bool forceNoManifest = false;
const std::string parameter ) const bool forceInstallManifest = false;
const bool forceRemoveManifest = false;
};
// Manages the programs control flow and main settings.
class MyQApplication : public QApplication
{ {
// The old way was one giant loop that tested every single parameter. public:
// Having an individual loop for all args most likely has a very small using QApplication::QApplication;
// performance penalty compared to the original solution, but the gains in
// readability and ease of extension of not having a hundred line+ for loop // Intercept event calls and log them on exceptions.
// are worth it. // From the official docs
for ( int i = 0; i < argc; i++ ) // https://doc.qt.io/qt-5/qcoreapplication.html#notify:
// "Future direction:
// This function will not be called for objects that live outside the main
// thread in Qt 6. Applications that need that functionality should find
// other solutions for their event inspection needs in the meantime. The
// change may be extended to the main thread, causing this function to be
// deprecated."
// Should look into replacements for this function if Qt 6 ever rolls
// around. There are multiple suggestions for other solutions in the
// provided link.
virtual bool notify( QObject* receiver, QEvent* event ) override
{ {
if ( std::string( argv[i] ) == parameter ) try
{ {
return true; return QApplication::notify( receiver, event );
} }
catch ( std::exception& e )
{
LOG( ERROR ) << "Exception thrown from an event handler: "
<< e.what();
}
return false;
}
};
// The default Qt message handler prints to stdout on X11 and to the debugger on
// Windows. That is borderline useless for us, therefore we create our own
// message handler.
void mainQtMessageHandler( QtMsgType type,
const QMessageLogContext& context,
const QString& msg )
{
QByteArray localMsg = msg.toLocal8Bit();
switch ( type )
{
case QtDebugMsg:
LOG( DEBUG ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
case QtInfoMsg:
LOG( INFO ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
case QtWarningMsg:
LOG( WARNING ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
case QtCriticalMsg:
LOG( ERROR ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
case QtFatalMsg:
LOG( FATAL ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
} }
return false;
} }
constexpr auto kDesktopMode = "-desktop"; namespace argument
constexpr auto kNoSound = "-nosound"; {
constexpr auto kNoManifest = "-nomanifest"; constexpr auto k_desktopMode = "desktop-mode";
constexpr auto kInstallManifest = "-installmanifest"; constexpr auto k_desktopModeDescription
constexpr auto kRemoveManifest = "-removemanifest"; = "Shows the options panel on the desktop instead of in VR.";
constexpr auto k_forceNoSound = "force-no-sound";
constexpr auto k_forceNoSoundDescription
= "Forces sounds off for the application.";
constexpr auto k_forceNoManifest = "force-no-manifest";
constexpr auto k_forceNoManifestDescription
= "Runs the application without installing the applications manifest.";
constexpr auto k_forceInstallManifest = "force-install-manifest";
constexpr auto k_forceInstallManifestDescription
= "Forces installing the applications manifest into SteamVR. Application "
"will exit early.";
constexpr auto k_forceRemoveManifest = "force-remove-anifest";
constexpr auto k_forceRemoveManifestDescription
= "Forces removing the applications manifest. Application will exit early.";
CommandLineOptions returnCommandLineParser( const MyQApplication& application )
{
QCommandLineParser parser;
parser.setApplicationDescription(
"Advanced Settings overlay for SteamVR." );
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption desktopMode( k_desktopMode, k_desktopModeDescription );
parser.addOption( desktopMode );
QCommandLineOption forceNoSound( k_forceNoSound,
k_forceNoSoundDescription );
parser.addOption( forceNoSound );
QCommandLineOption forceNoManifest( k_forceNoManifest,
k_forceNoManifestDescription );
parser.addOption( forceNoManifest );
QCommandLineOption forceInstallManifest(
k_forceInstallManifest, k_forceInstallManifestDescription );
parser.addOption( forceInstallManifest );
QCommandLineOption forceRemoveManifest( k_forceRemoveManifest,
k_forceRemoveManifestDescription );
parser.addOption( forceRemoveManifest );
parser.process( application );
const bool desktopModeEnabled = parser.isSet( desktopMode );
LOG_IF( desktopModeEnabled, INFO ) << "Desktop mode enabled.";
const bool forceNoSoundEnabled = parser.isSet( forceNoSound );
LOG_IF( forceNoSoundEnabled, INFO ) << "Sound effects disabled.";
const bool forceNoManifestEnabled = parser.isSet( forceNoManifest );
LOG_IF( forceNoManifestEnabled, INFO )
<< "Running without applications manifest.";
const bool forceInstallManifestEnabled
= parser.isSet( forceInstallManifest );
LOG_IF( forceInstallManifestEnabled, INFO )
<< "Forcing install of applications manifest.";
const bool forceRemoveManifestEnabled = parser.isSet( forceRemoveManifest );
LOG_IF( forceRemoveManifestEnabled, INFO )
<< "Forcing removal of applications manifest.";
const CommandLineOptions commandLineArgs{ desktopModeEnabled,
forceNoSoundEnabled,
forceNoManifestEnabled,
forceInstallManifestEnabled,
forceRemoveManifestEnabled };
LOG( INFO ) << "Command line arguments processed.";
return commandLineArgs;
}
} // namespace argument } // namespace argument
namespace manifest namespace manifest
@@ -275,69 +405,3 @@ void setUpLogging( int argc, char* argv[] )
<< QDir::toNativeSeparators( logconfigfile ).toStdString(); << QDir::toNativeSeparators( logconfigfile ).toStdString();
LOG( INFO ) << "Log File: " << logFilePath; LOG( INFO ) << "Log File: " << logFilePath;
} }
// Manages the programs control flow and main settings.
class MyQApplication : public QApplication
{
public:
using QApplication::QApplication;
// Intercept event calls and log them on exceptions.
// From the official docs
// https://doc.qt.io/qt-5/qcoreapplication.html#notify:
// "Future direction:
// This function will not be called for objects that live outside the main
// thread in Qt 6. Applications that need that functionality should find
// other solutions for their event inspection needs in the meantime. The
// change may be extended to the main thread, causing this function to be
// deprecated."
// Should look into replacements for this function if Qt 6 ever rolls
// around. There are multiple suggestions for other solutions in the
// provided link.
virtual bool notify( QObject* receiver, QEvent* event ) override
{
try
{
return QApplication::notify( receiver, event );
}
catch ( std::exception& e )
{
LOG( ERROR ) << "Exception thrown from an event handler: "
<< e.what();
}
return false;
}
};
// The default Qt message handler prints to stdout on X11 and to the debugger on
// Windows. That is borderline useless for us, therefore we create our own
// message handler.
void mainQtMessageHandler( QtMsgType type,
const QMessageLogContext& context,
const QString& msg )
{
QByteArray localMsg = msg.toLocal8Bit();
switch ( type )
{
case QtDebugMsg:
LOG( DEBUG ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
case QtInfoMsg:
LOG( INFO ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
case QtWarningMsg:
LOG( WARNING ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
case QtCriticalMsg:
LOG( ERROR ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
case QtFatalMsg:
LOG( FATAL ) << localMsg.constData() << " (" << context.file << ":"
<< context.line << ")";
break;
}
}