1 /* 2 * Copyright (C) 2009, 2010, 2011, 2013, 2014 Nicolas Bonnefon and other contributors 3 * 4 * This file is part of glogg. 5 * 6 * glogg is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * glogg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with glogg. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <QApplication> 21 #include <QFileInfo> 22 23 #include <memory> 24 25 #include <boost/program_options.hpp> 26 namespace po = boost::program_options; 27 28 #include <iostream> 29 #include <iomanip> 30 using namespace std; 31 32 #ifdef _WIN32 33 #include "unistd.h" 34 #endif 35 36 #include "persistentinfo.h" 37 #include "sessioninfo.h" 38 #include "configuration.h" 39 #include "filterset.h" 40 #include "recentfiles.h" 41 #include "session.h" 42 #include "mainwindow.h" 43 #include "savedsearches.h" 44 #include "loadingstatus.h" 45 46 #include "externalcom.h" 47 #ifdef GLOGG_SUPPORTS_DBUS 48 #include "dbusexternalcom.h" 49 #elif GLOGG_SUPPORTS_WINIPC 50 #include "winexternalcom.h" 51 #endif 52 53 54 #include "log.h" 55 56 static void print_version(); 57 58 int main(int argc, char *argv[]) 59 { 60 QApplication app(argc, argv); 61 62 string filename = ""; 63 64 // Configuration 65 bool new_session = false; 66 bool load_session = false; 67 bool multi_instance = false; 68 #ifdef _WIN32 69 bool log_to_file = false; 70 #endif 71 72 TLogLevel logLevel = logWARNING; 73 74 try { 75 po::options_description desc("Usage: glogg [options] [file]"); 76 desc.add_options() 77 ("help,h", "print out program usage (this message)") 78 ("version,v", "print glogg's version information") 79 ("multi,m", "allow multiple instance of glogg to run simultaneously (use together with -s)") 80 ("load-session,s", "load the previous session (default when no file is passed)") 81 ("new-session,n", "do not load the previous session (default when a file is passed)") 82 #ifdef _WIN32 83 ("log,l", "save the log to a file (Windows only)") 84 #endif 85 ("debug,d", "output more debug (include multiple times for more verbosity e.g. -dddd)") 86 ; 87 po::options_description desc_hidden("Hidden options"); 88 // For -dd, -ddd... 89 for ( string s = "dd"; s.length() <= 10; s.append("d") ) 90 desc_hidden.add_options()(s.c_str(), "debug"); 91 92 desc_hidden.add_options() 93 ("input-file", po::value<string>(), "input file") 94 ; 95 96 po::options_description all_options("all options"); 97 all_options.add(desc).add(desc_hidden); 98 99 po::positional_options_description positional; 100 positional.add("input-file", 1); 101 102 int command_line_style = (((po::command_line_style::unix_style ^ 103 po::command_line_style::allow_guessing) | 104 po::command_line_style::allow_long_disguise) ^ 105 po::command_line_style::allow_sticky); 106 107 po::variables_map vm; 108 po::store(po::command_line_parser(argc, argv). 109 options(all_options). 110 positional(positional). 111 style(command_line_style).run(), 112 vm); 113 po::notify(vm); 114 115 if ( vm.count("help") ) { 116 desc.print(cout); 117 return 0; 118 } 119 120 if ( vm.count("version") ) { 121 print_version(); 122 return 0; 123 } 124 125 if ( vm.count( "debug" ) ) 126 logLevel = logINFO; 127 128 if ( vm.count( "multi" ) ) 129 multi_instance = true; 130 131 if ( vm.count( "new-session" ) ) 132 new_session = true; 133 134 if ( vm.count( "load-session" ) ) 135 load_session = true; 136 137 #ifdef _WIN32 138 if ( vm.count( "log" ) ) 139 log_to_file = true; 140 #endif 141 142 for ( string s = "dd"; s.length() <= 10; s.append("d") ) 143 if ( vm.count( s ) ) 144 logLevel = (TLogLevel) (logWARNING + s.length()); 145 146 if ( vm.count("input-file") ) { 147 filename = vm["input-file"].as<string>(); 148 } 149 } 150 catch(exception& e) { 151 cerr << "Option processing error: " << e.what() << endl; 152 return 1; 153 } 154 catch(...) { 155 cerr << "Exception of unknown type!\n"; 156 } 157 158 #ifdef _WIN32 159 if ( log_to_file ) 160 { 161 char file_name[255]; 162 snprintf( file_name, sizeof file_name, "glogg_%d.log", getpid() ); 163 FILE* file = fopen(file_name, "w"); 164 Output2FILE::Stream() = file; 165 } 166 #endif 167 168 FILELog::setReportingLevel( logLevel ); 169 170 if ( ! filename.empty() ) { 171 // Convert to absolute path 172 QFileInfo file( QString::fromLocal8Bit( filename.c_str() ) ); 173 filename = file.absoluteFilePath().toStdString(); 174 LOG( logDEBUG ) << "Filename: " << filename; 175 } 176 177 // External communicator 178 shared_ptr<ExternalCommunicator> externalCommunicator = nullptr; 179 shared_ptr<ExternalInstance> externalInstance = nullptr; 180 181 try { 182 #ifdef GLOGG_SUPPORTS_DBUS 183 externalCommunicator = make_shared<DBusExternalCommunicator>(); 184 externalInstance = shared_ptr<ExternalInstance>( 185 externalCommunicator->otherInstance() ); 186 #elif GLOGG_SUPPORTS_WINIPC 187 externalCommunicator = make_shared<WinExternalCommunicator>(); 188 externalInstance = shared_ptr<ExternalInstance>( 189 externalCommunicator->otherInstance() ); 190 #endif 191 } 192 catch(CantCreateExternalErr& e) { 193 LOG(logWARNING) << "Cannot initialise external communication."; 194 } 195 196 LOG(logDEBUG) << "externalInstance = " << externalInstance; 197 if ( ( ! multi_instance ) && externalInstance ) { 198 uint32_t version = externalInstance->getVersion(); 199 LOG(logINFO) << "Found another glogg (version = " 200 << std::setbase(16) << version << ")"; 201 202 externalInstance->loadFile( QString::fromStdString( filename ) ); 203 204 return 0; 205 } 206 else { 207 // FIXME: there is a race condition here. One glogg could start 208 // between the declaration of externalInstance and here, 209 // is it a problem? 210 if ( externalCommunicator ) 211 externalCommunicator->startListening(); 212 } 213 214 // Register types for Qt 215 qRegisterMetaType<LoadingStatus>("LoadingStatus"); 216 217 // Register the configuration items 218 GetPersistentInfo().migrateAndInit(); 219 GetPersistentInfo().registerPersistable( 220 std::make_shared<SessionInfo>(), QString( "session" ) ); 221 GetPersistentInfo().registerPersistable( 222 std::make_shared<Configuration>(), QString( "settings" ) ); 223 GetPersistentInfo().registerPersistable( 224 std::make_shared<FilterSet>(), QString( "filterSet" ) ); 225 GetPersistentInfo().registerPersistable( 226 std::make_shared<SavedSearches>(), QString( "savedSearches" ) ); 227 GetPersistentInfo().registerPersistable( 228 std::make_shared<RecentFiles>(), QString( "recentFiles" ) ); 229 #ifdef GLOGG_SUPPORTS_VERSION_CHECKING 230 GetPersistentInfo().registerPersistable( 231 std::make_shared<VersionCheckerConfig>(), QString( "versionChecker" ) ); 232 #endif 233 234 #ifdef _WIN32 235 // Allow the app to raise it's own windows (in case an external 236 // glogg send us a file to open) 237 AllowSetForegroundWindow(ASFW_ANY); 238 #endif 239 240 // We support high-dpi (aka Retina) displays 241 app.setAttribute( Qt::AA_UseHighDpiPixmaps ); 242 243 // No icon in menus 244 app.setAttribute( Qt::AA_DontShowIconsInMenus ); 245 246 // FIXME: should be replaced by a two staged init of MainWindow 247 GetPersistentInfo().retrieve( QString( "settings" ) ); 248 249 std::unique_ptr<Session> session( new Session() ); 250 MainWindow mw( std::move( session ), externalCommunicator ); 251 252 LOG(logDEBUG) << "MainWindow created."; 253 mw.show(); 254 255 // Load the existing session if needed 256 std::shared_ptr<Configuration> config = 257 Persistent<Configuration>( "settings" ); 258 if ( load_session || ( filename.empty() && !new_session && config->loadLastSession() ) ) 259 mw.reloadSession(); 260 261 mw.loadInitialFile( QString::fromStdString( filename ) ); 262 mw.startBackgroundTasks(); 263 264 return app.exec(); 265 } 266 267 static void print_version() 268 { 269 cout << "glogg " GLOGG_VERSION "\n"; 270 #ifdef GLOGG_COMMIT 271 cout << "Built " GLOGG_DATE " from " GLOGG_COMMIT "\n"; 272 #endif 273 cout << "Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicolas Bonnefon and other contributors\n"; 274 cout << "This is free software. You may redistribute copies of it under the terms of\n"; 275 cout << "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"; 276 cout << "There is NO WARRANTY, to the extent permitted by law.\n"; 277 } 278