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