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
main(int argc,char * argv[])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
print_version()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