]>
Commit | Line | Data |
---|---|---|
f914f1a7 | 1 | // Copyright (c) 2011-2014 The Bitcoin Core developers |
78253fcb | 2 | // Distributed under the MIT software license, see the accompanying |
e592d43f | 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
32af5266 | 4 | |
245a6ab1 | 5 | #if defined(HAVE_CONFIG_H) |
f3967bcc | 6 | #include "config/bitcoin-config.h" |
245a6ab1 PK |
7 | #endif |
8 | ||
0fd01780 | 9 | #include "bitcoingui.h" |
51ed9ec9 | 10 | |
18cab09a | 11 | #include "clientmodel.h" |
3793fa09 | 12 | #include "guiconstants.h" |
51ed9ec9 BD |
13 | #include "guiutil.h" |
14 | #include "intro.h" | |
6de50c3c | 15 | #include "networkstyle.h" |
51ed9ec9 | 16 | #include "optionsmodel.h" |
f9124587 | 17 | #include "splashscreen.h" |
7b50bb2f | 18 | #include "utilitydialog.h" |
d282c1fb | 19 | #include "winshutdownmonitor.h" |
5e83bc40 | 20 | |
b7f4b6d3 WL |
21 | #ifdef ENABLE_WALLET |
22 | #include "paymentserver.h" | |
51ed9ec9 | 23 | #include "walletmodel.h" |
b7f4b6d3 | 24 | #endif |
51ed9ec9 BD |
25 | |
26 | #include "init.h" | |
27 | #include "main.h" | |
a8db31c8 | 28 | #include "rpcserver.h" |
ddd0acd3 | 29 | #include "scheduler.h" |
51ed9ec9 BD |
30 | #include "ui_interface.h" |
31 | #include "util.h" | |
5e83bc40 | 32 | |
65adc3a8 | 33 | #ifdef ENABLE_WALLET |
50c72f23 | 34 | #include "wallet/wallet.h" |
65adc3a8 | 35 | #endif |
aaa1c3c4 | 36 | |
51ed9ec9 BD |
37 | #include <stdint.h> |
38 | ||
39 | #include <boost/filesystem/operations.hpp> | |
ad49c256 | 40 | #include <boost/thread.hpp> |
5e83bc40 | 41 | |
84ef729a | 42 | #include <QApplication> |
c715ff52 | 43 | #include <QDebug> |
51ed9ec9 BD |
44 | #include <QLibraryInfo> |
45 | #include <QLocale> | |
467c31ea | 46 | #include <QMessageBox> |
51ed9ec9 | 47 | #include <QSettings> |
5e83bc40 | 48 | #include <QThread> |
51ed9ec9 BD |
49 | #include <QTimer> |
50 | #include <QTranslator> | |
8e5a9690 | 51 | #include <QSslConfiguration> |
51ed9ec9 | 52 | |
60dc5894 | 53 | #if defined(QT_STATICPLUGIN) |
55f69a47 | 54 | #include <QtPlugin> |
60dc5894 | 55 | #if QT_VERSION < 0x050000 |
55f69a47 WL |
56 | Q_IMPORT_PLUGIN(qcncodecs) |
57 | Q_IMPORT_PLUGIN(qjpcodecs) | |
58 | Q_IMPORT_PLUGIN(qtwcodecs) | |
59 | Q_IMPORT_PLUGIN(qkrcodecs) | |
60 | Q_IMPORT_PLUGIN(qtaccessiblewidgets) | |
60dc5894 | 61 | #else |
92401c2d | 62 | #if QT_VERSION < 0x050400 |
60dc5894 | 63 | Q_IMPORT_PLUGIN(AccessibleFactory) |
92401c2d | 64 | #endif |
ab123ad4 CF |
65 | #if defined(QT_QPA_PLATFORM_XCB) |
66 | Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); | |
67 | #elif defined(QT_QPA_PLATFORM_WINDOWS) | |
60dc5894 | 68 | Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); |
ab123ad4 CF |
69 | #elif defined(QT_QPA_PLATFORM_COCOA) |
70 | Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); | |
71 | #endif | |
60dc5894 CF |
72 | #endif |
73 | #endif | |
74 | ||
75 | #if QT_VERSION < 0x050000 | |
76 | #include <QTextCodec> | |
55f69a47 WL |
77 | #endif |
78 | ||
e83a90f1 WL |
79 | // Declare meta types used for QMetaObject::invokeMethod |
80 | Q_DECLARE_METATYPE(bool*) | |
c122f552 | 81 | Q_DECLARE_METATYPE(CAmount) |
e83a90f1 | 82 | |
ab1b288f | 83 | static void InitMessage(const std::string &message) |
10d680cf | 84 | { |
7d9d134b | 85 | LogPrintf("init message: %s\n", message); |
10d680cf WL |
86 | } |
87 | ||
39cf857d WL |
88 | /* |
89 | Translate string to current locale using Qt. | |
90 | */ | |
ab1b288f | 91 | static std::string Translate(const char* psz) |
39cf857d WL |
92 | { |
93 | return QCoreApplication::translate("bitcoin-core", psz).toStdString(); | |
94 | } | |
95 | ||
f5ad78b3 CF |
96 | static QString GetLangTerritory() |
97 | { | |
98 | QSettings settings; | |
99 | // Get desired locale (e.g. "de_DE") | |
100 | // 1) System default language | |
101 | QString lang_territory = QLocale::system().name(); | |
102 | // 2) Language from QSettings | |
103 | QString lang_territory_qsettings = settings.value("language", "").toString(); | |
104 | if(!lang_territory_qsettings.isEmpty()) | |
105 | lang_territory = lang_territory_qsettings; | |
106 | // 3) -lang command line argument | |
107 | lang_territory = QString::fromStdString(GetArg("-lang", lang_territory.toStdString())); | |
108 | return lang_territory; | |
109 | } | |
110 | ||
be77b637 WL |
111 | /** Set up translations */ |
112 | static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator) | |
113 | { | |
c52c4e5d WL |
114 | // Remove old translators |
115 | QApplication::removeTranslator(&qtTranslatorBase); | |
116 | QApplication::removeTranslator(&qtTranslator); | |
117 | QApplication::removeTranslator(&translatorBase); | |
118 | QApplication::removeTranslator(&translator); | |
119 | ||
be77b637 WL |
120 | // Get desired locale (e.g. "de_DE") |
121 | // 1) System default language | |
f5ad78b3 | 122 | QString lang_territory = GetLangTerritory(); |
be77b637 WL |
123 | |
124 | // Convert to "de" only by truncating "_DE" | |
125 | QString lang = lang_territory; | |
126 | lang.truncate(lang_territory.lastIndexOf('_')); | |
127 | ||
128 | // Load language files for configured locale: | |
129 | // - First load the translator for the base language, without territory | |
130 | // - Then load the more specific locale translator | |
131 | ||
132 | // Load e.g. qt_de.qm | |
133 | if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) | |
134 | QApplication::installTranslator(&qtTranslatorBase); | |
135 | ||
136 | // Load e.g. qt_de_DE.qm | |
137 | if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) | |
138 | QApplication::installTranslator(&qtTranslator); | |
139 | ||
140 | // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc) | |
141 | if (translatorBase.load(lang, ":/translations/")) | |
142 | QApplication::installTranslator(&translatorBase); | |
143 | ||
144 | // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc) | |
145 | if (translator.load(lang_territory, ":/translations/")) | |
146 | QApplication::installTranslator(&translator); | |
147 | } | |
148 | ||
47d05343 GA |
149 | /* qDebug() message handler --> debug.log */ |
150 | #if QT_VERSION < 0x050000 | |
ccd1372d | 151 | void DebugMessageHandler(QtMsgType type, const char *msg) |
47d05343 | 152 | { |
d95ba758 WL |
153 | const char *category = (type == QtDebugMsg) ? "qt" : NULL; |
154 | LogPrint(category, "GUI: %s\n", msg); | |
47d05343 GA |
155 | } |
156 | #else | |
157 | void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg) | |
158 | { | |
d5f0ef54 | 159 | Q_UNUSED(context); |
d95ba758 | 160 | const char *category = (type == QtDebugMsg) ? "qt" : NULL; |
2882d594 | 161 | LogPrint(category, "GUI: %s\n", msg.toStdString()); |
47d05343 GA |
162 | } |
163 | #endif | |
164 | ||
202d853b WL |
165 | /** Class encapsulating Bitcoin Core startup and shutdown. |
166 | * Allows running startup and shutdown in a different thread from the UI thread. | |
167 | */ | |
168 | class BitcoinCore: public QObject | |
169 | { | |
170 | Q_OBJECT | |
171 | public: | |
172 | explicit BitcoinCore(); | |
173 | ||
e092f229 | 174 | public Q_SLOTS: |
202d853b WL |
175 | void initialize(); |
176 | void shutdown(); | |
177 | ||
e092f229 | 178 | Q_SIGNALS: |
202d853b WL |
179 | void initializeResult(int retval); |
180 | void shutdownResult(int retval); | |
181 | void runawayException(const QString &message); | |
182 | ||
183 | private: | |
184 | boost::thread_group threadGroup; | |
ddd0acd3 | 185 | CScheduler scheduler; |
202d853b WL |
186 | |
187 | /// Pass fatal exception message to UI thread | |
27df4123 | 188 | void handleRunawayException(const std::exception *e); |
202d853b WL |
189 | }; |
190 | ||
191 | /** Main Bitcoin application object */ | |
192 | class BitcoinApplication: public QApplication | |
193 | { | |
194 | Q_OBJECT | |
195 | public: | |
196 | explicit BitcoinApplication(int &argc, char **argv); | |
197 | ~BitcoinApplication(); | |
198 | ||
b7f4b6d3 | 199 | #ifdef ENABLE_WALLET |
202d853b WL |
200 | /// Create payment server |
201 | void createPaymentServer(); | |
b7f4b6d3 | 202 | #endif |
202d853b WL |
203 | /// Create options model |
204 | void createOptionsModel(); | |
205 | /// Create main window | |
6de50c3c | 206 | void createWindow(const NetworkStyle *networkStyle); |
35ecf854 | 207 | /// Create splash screen |
6de50c3c | 208 | void createSplashScreen(const NetworkStyle *networkStyle); |
202d853b WL |
209 | |
210 | /// Request core initialization | |
211 | void requestInitialize(); | |
212 | /// Request core shutdown | |
213 | void requestShutdown(); | |
214 | ||
215 | /// Get process return value | |
216 | int getReturnValue() { return returnValue; } | |
217 | ||
d282c1fb PK |
218 | /// Get window identifier of QMainWindow (BitcoinGUI) |
219 | WId getMainWinId() const; | |
220 | ||
e092f229 | 221 | public Q_SLOTS: |
202d853b WL |
222 | void initializeResult(int retval); |
223 | void shutdownResult(int retval); | |
224 | /// Handle runaway exceptions. Shows a message box with the problem and quits the program. | |
225 | void handleRunawayException(const QString &message); | |
226 | ||
e092f229 | 227 | Q_SIGNALS: |
202d853b WL |
228 | void requestedInitialize(); |
229 | void requestedShutdown(); | |
230 | void stopThread(); | |
35ecf854 | 231 | void splashFinished(QWidget *window); |
202d853b WL |
232 | |
233 | private: | |
234 | QThread *coreThread; | |
202d853b WL |
235 | OptionsModel *optionsModel; |
236 | ClientModel *clientModel; | |
237 | BitcoinGUI *window; | |
9a2305a1 | 238 | QTimer *pollShutdownTimer; |
b7f4b6d3 WL |
239 | #ifdef ENABLE_WALLET |
240 | PaymentServer* paymentServer; | |
241 | WalletModel *walletModel; | |
242 | #endif | |
202d853b WL |
243 | int returnValue; |
244 | ||
245 | void startThread(); | |
246 | }; | |
247 | ||
248 | #include "bitcoin.moc" | |
249 | ||
250 | BitcoinCore::BitcoinCore(): | |
251 | QObject() | |
252 | { | |
253 | } | |
254 | ||
27df4123 | 255 | void BitcoinCore::handleRunawayException(const std::exception *e) |
202d853b WL |
256 | { |
257 | PrintExceptionContinue(e, "Runaway exception"); | |
e092f229 | 258 | Q_EMIT runawayException(QString::fromStdString(strMiscWarning)); |
202d853b WL |
259 | } |
260 | ||
261 | void BitcoinCore::initialize() | |
262 | { | |
263 | try | |
264 | { | |
c715ff52 | 265 | qDebug() << __func__ << ": Running AppInit2 in thread"; |
ddd0acd3 | 266 | int rv = AppInit2(threadGroup, scheduler); |
a8db31c8 WL |
267 | if(rv) |
268 | { | |
269 | /* Start a dummy RPC thread if no RPC thread is active yet | |
270 | * to handle timeouts. | |
271 | */ | |
272 | StartDummyRPCThread(); | |
273 | } | |
e092f229 | 274 | Q_EMIT initializeResult(rv); |
27df4123 | 275 | } catch (const std::exception& e) { |
202d853b WL |
276 | handleRunawayException(&e); |
277 | } catch (...) { | |
278 | handleRunawayException(NULL); | |
279 | } | |
280 | } | |
281 | ||
282 | void BitcoinCore::shutdown() | |
283 | { | |
284 | try | |
285 | { | |
c715ff52 | 286 | qDebug() << __func__ << ": Running Shutdown in thread"; |
202d853b WL |
287 | threadGroup.interrupt_all(); |
288 | threadGroup.join_all(); | |
289 | Shutdown(); | |
c715ff52 | 290 | qDebug() << __func__ << ": Shutdown finished"; |
e092f229 | 291 | Q_EMIT shutdownResult(1); |
27df4123 | 292 | } catch (const std::exception& e) { |
202d853b WL |
293 | handleRunawayException(&e); |
294 | } catch (...) { | |
295 | handleRunawayException(NULL); | |
296 | } | |
297 | } | |
298 | ||
299 | BitcoinApplication::BitcoinApplication(int &argc, char **argv): | |
300 | QApplication(argc, argv), | |
301 | coreThread(0), | |
202d853b WL |
302 | optionsModel(0), |
303 | clientModel(0), | |
304 | window(0), | |
9a2305a1 | 305 | pollShutdownTimer(0), |
b7f4b6d3 WL |
306 | #ifdef ENABLE_WALLET |
307 | paymentServer(0), | |
308 | walletModel(0), | |
309 | #endif | |
202d853b WL |
310 | returnValue(0) |
311 | { | |
312 | setQuitOnLastWindowClosed(false); | |
202d853b WL |
313 | } |
314 | ||
315 | BitcoinApplication::~BitcoinApplication() | |
316 | { | |
33357b27 WL |
317 | if(coreThread) |
318 | { | |
319 | qDebug() << __func__ << ": Stopping thread"; | |
e092f229 | 320 | Q_EMIT stopThread(); |
33357b27 WL |
321 | coreThread->wait(); |
322 | qDebug() << __func__ << ": Stopped thread"; | |
323 | } | |
35ecf854 WL |
324 | |
325 | delete window; | |
b7f4b6d3 WL |
326 | window = 0; |
327 | #ifdef ENABLE_WALLET | |
35ecf854 | 328 | delete paymentServer; |
b7f4b6d3 WL |
329 | paymentServer = 0; |
330 | #endif | |
35ecf854 | 331 | delete optionsModel; |
b7f4b6d3 | 332 | optionsModel = 0; |
202d853b WL |
333 | } |
334 | ||
b7f4b6d3 | 335 | #ifdef ENABLE_WALLET |
202d853b WL |
336 | void BitcoinApplication::createPaymentServer() |
337 | { | |
338 | paymentServer = new PaymentServer(this); | |
339 | } | |
b7f4b6d3 | 340 | #endif |
202d853b WL |
341 | |
342 | void BitcoinApplication::createOptionsModel() | |
343 | { | |
344 | optionsModel = new OptionsModel(); | |
345 | } | |
346 | ||
6de50c3c | 347 | void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) |
202d853b | 348 | { |
6de50c3c | 349 | window = new BitcoinGUI(networkStyle, 0); |
202d853b | 350 | |
9a2305a1 | 351 | pollShutdownTimer = new QTimer(window); |
202d853b WL |
352 | connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown())); |
353 | pollShutdownTimer->start(200); | |
354 | } | |
355 | ||
6de50c3c | 356 | void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) |
35ecf854 | 357 | { |
6de50c3c | 358 | SplashScreen *splash = new SplashScreen(0, networkStyle); |
cfc5cfb0 WL |
359 | // We don't hold a direct pointer to the splash screen after creation, so use |
360 | // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually. | |
361 | splash->setAttribute(Qt::WA_DeleteOnClose); | |
35ecf854 WL |
362 | splash->show(); |
363 | connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*))); | |
364 | } | |
365 | ||
202d853b WL |
366 | void BitcoinApplication::startThread() |
367 | { | |
33357b27 WL |
368 | if(coreThread) |
369 | return; | |
202d853b WL |
370 | coreThread = new QThread(this); |
371 | BitcoinCore *executor = new BitcoinCore(); | |
372 | executor->moveToThread(coreThread); | |
373 | ||
374 | /* communication to and from thread */ | |
375 | connect(executor, SIGNAL(initializeResult(int)), this, SLOT(initializeResult(int))); | |
376 | connect(executor, SIGNAL(shutdownResult(int)), this, SLOT(shutdownResult(int))); | |
377 | connect(executor, SIGNAL(runawayException(QString)), this, SLOT(handleRunawayException(QString))); | |
378 | connect(this, SIGNAL(requestedInitialize()), executor, SLOT(initialize())); | |
379 | connect(this, SIGNAL(requestedShutdown()), executor, SLOT(shutdown())); | |
380 | /* make sure executor object is deleted in its own thread */ | |
381 | connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater())); | |
382 | connect(this, SIGNAL(stopThread()), coreThread, SLOT(quit())); | |
383 | ||
384 | coreThread->start(); | |
385 | } | |
386 | ||
387 | void BitcoinApplication::requestInitialize() | |
388 | { | |
c715ff52 | 389 | qDebug() << __func__ << ": Requesting initialize"; |
33357b27 | 390 | startThread(); |
e092f229 | 391 | Q_EMIT requestedInitialize(); |
202d853b WL |
392 | } |
393 | ||
394 | void BitcoinApplication::requestShutdown() | |
395 | { | |
c715ff52 | 396 | qDebug() << __func__ << ": Requesting shutdown"; |
33357b27 | 397 | startThread(); |
202d853b WL |
398 | window->hide(); |
399 | window->setClientModel(0); | |
9a2305a1 | 400 | pollShutdownTimer->stop(); |
55fe4de9 | 401 | |
b7f4b6d3 WL |
402 | #ifdef ENABLE_WALLET |
403 | window->removeAllWallets(); | |
202d853b | 404 | delete walletModel; |
35ecf854 | 405 | walletModel = 0; |
b7f4b6d3 | 406 | #endif |
35ecf854 WL |
407 | delete clientModel; |
408 | clientModel = 0; | |
55fe4de9 WL |
409 | |
410 | // Show a simple window indicating shutdown status | |
7b50bb2f | 411 | ShutdownWindow::showShutdownWindow(window); |
55fe4de9 WL |
412 | |
413 | // Request shutdown from core thread | |
e092f229 | 414 | Q_EMIT requestedShutdown(); |
202d853b WL |
415 | } |
416 | ||
417 | void BitcoinApplication::initializeResult(int retval) | |
418 | { | |
c715ff52 | 419 | qDebug() << __func__ << ": Initialization result: " << retval; |
55fe4de9 | 420 | // Set exit result: 0 if successful, 1 if failure |
202d853b WL |
421 | returnValue = retval ? 0 : 1; |
422 | if(retval) | |
423 | { | |
b7f4b6d3 | 424 | #ifdef ENABLE_WALLET |
202d853b WL |
425 | PaymentServer::LoadRootCAs(); |
426 | paymentServer->setOptionsModel(optionsModel); | |
b7f4b6d3 | 427 | #endif |
202d853b | 428 | |
202d853b WL |
429 | clientModel = new ClientModel(optionsModel); |
430 | window->setClientModel(clientModel); | |
431 | ||
b7f4b6d3 | 432 | #ifdef ENABLE_WALLET |
202d853b WL |
433 | if(pwalletMain) |
434 | { | |
435 | walletModel = new WalletModel(pwalletMain, optionsModel); | |
436 | ||
314fbd9a PK |
437 | window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel); |
438 | window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET); | |
202d853b WL |
439 | |
440 | connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)), | |
441 | paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray))); | |
442 | } | |
b7f4b6d3 | 443 | #endif |
202d853b WL |
444 | |
445 | // If -min option passed, start window minimized. | |
446 | if(GetBoolArg("-min", false)) | |
447 | { | |
448 | window->showMinimized(); | |
449 | } | |
450 | else | |
451 | { | |
452 | window->show(); | |
453 | } | |
e092f229 | 454 | Q_EMIT splashFinished(window); |
a49f11d9 | 455 | |
b7f4b6d3 | 456 | #ifdef ENABLE_WALLET |
202d853b WL |
457 | // Now that initialization/startup is done, process any command-line |
458 | // bitcoin: URIs or payment requests: | |
459 | connect(paymentServer, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)), | |
460 | window, SLOT(handlePaymentRequest(SendCoinsRecipient))); | |
461 | connect(window, SIGNAL(receivedURI(QString)), | |
462 | paymentServer, SLOT(handleURIOrFile(QString))); | |
463 | connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)), | |
464 | window, SLOT(message(QString,QString,unsigned int))); | |
465 | QTimer::singleShot(100, paymentServer, SLOT(uiReady())); | |
b7f4b6d3 | 466 | #endif |
202d853b WL |
467 | } else { |
468 | quit(); // Exit main loop | |
469 | } | |
470 | } | |
471 | ||
472 | void BitcoinApplication::shutdownResult(int retval) | |
473 | { | |
c715ff52 | 474 | qDebug() << __func__ << ": Shutdown result: " << retval; |
202d853b WL |
475 | quit(); // Exit main loop after shutdown finished |
476 | } | |
477 | ||
478 | void BitcoinApplication::handleRunawayException(const QString &message) | |
479 | { | |
480 | QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message); | |
481 | ::exit(1); | |
482 | } | |
483 | ||
d282c1fb PK |
484 | WId BitcoinApplication::getMainWinId() const |
485 | { | |
486 | if (!window) | |
487 | return 0; | |
488 | ||
489 | return window->winId(); | |
490 | } | |
491 | ||
24548467 | 492 | #ifndef BITCOIN_QT_TEST |
aaa1c3c4 WL |
493 | int main(int argc, char *argv[]) |
494 | { | |
5248ff40 SC |
495 | SetupEnvironment(); |
496 | ||
2102ab9f | 497 | /// 1. Parse command-line options. These take precedence over anything else. |
8ffbd6c3 PK |
498 | // Command-line options take precedence: |
499 | ParseParameters(argc, argv); | |
2102ab9f WL |
500 | |
501 | // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory | |
8ffbd6c3 | 502 | |
2102ab9f | 503 | /// 2. Basic Qt initialization (not dependent on parameters or configuration) |
25c0cce7 | 504 | #if QT_VERSION < 0x050000 |
c75abc9f | 505 | // Internal string conversion is all UTF-8 |
3f0816e3 MSV |
506 | QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); |
507 | QTextCodec::setCodecForCStrings(QTextCodec::codecForTr()); | |
25c0cce7 | 508 | #endif |
3f0816e3 | 509 | |
45c4a0b3 | 510 | Q_INIT_RESOURCE(bitcoin); |
38e324af | 511 | Q_INIT_RESOURCE(bitcoin_locale); |
292cc072 | 512 | |
202d853b | 513 | BitcoinApplication app(argc, argv); |
84f8551f PK |
514 | #if QT_VERSION > 0x050100 |
515 | // Generate high-dpi pixmaps | |
516 | QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); | |
517 | #endif | |
518 | #ifdef Q_OS_MAC | |
519 | QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); | |
520 | #endif | |
8e5a9690 WL |
521 | #if QT_VERSION >= 0x050500 |
522 | // Because of the POODLE attack it is recommended to disable SSLv3 (https://disablessl3.com/), | |
523 | // so set SSL protocols to TLS1.0+. | |
524 | QSslConfiguration sslconf = QSslConfiguration::defaultConfiguration(); | |
525 | sslconf.setProtocol(QSsl::TlsV1_0OrLater); | |
526 | QSslConfiguration::setDefaultConfiguration(sslconf); | |
527 | #endif | |
daaee738 | 528 | |
e83a90f1 WL |
529 | // Register meta types used for QMetaObject::invokeMethod |
530 | qRegisterMetaType< bool* >(); | |
c122f552 WL |
531 | // Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType) |
532 | // IMPORTANT if it is no longer a typedef use the normal variant above | |
533 | qRegisterMetaType< CAmount >("CAmount"); | |
e83a90f1 | 534 | |
2102ab9f WL |
535 | /// 3. Application identification |
536 | // must be set before OptionsModel is initialized or translations are loaded, | |
537 | // as it is used to locate QSettings | |
c52c4e5d WL |
538 | QApplication::setOrganizationName(QAPP_ORG_NAME); |
539 | QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN); | |
540 | QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT); | |
f5ad78b3 | 541 | GUIUtil::SubstituteFonts(GetLangTerritory()); |
be77b637 | 542 | |
2102ab9f | 543 | /// 4. Initialization of translations, so that intro dialog is in user's language |
be77b637 WL |
544 | // Now that QSettings are accessible, initialize translations |
545 | QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; | |
546 | initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); | |
b74dcb3b | 547 | translationInterface.Translate.connect(Translate); |
be77b637 | 548 | |
2102ab9f WL |
549 | // Show help message immediately after parsing command-line options (for "-lang") and setting locale, |
550 | // but before showing splash screen. | |
af6edac0 | 551 | if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) |
2102ab9f | 552 | { |
96b733e9 | 553 | HelpMessageDialog help(NULL, mapArgs.count("-version")); |
2102ab9f | 554 | help.showOrPrint(); |
a2189fba PK |
555 | return 1; |
556 | } | |
a2189fba | 557 | |
2102ab9f WL |
558 | /// 5. Now that settings and translations are available, ask user for data directory |
559 | // User language is set up: pick a data directory | |
c52c4e5d | 560 | Intro::pickDataDirectory(); |
2102ab9f | 561 | |
5166804f | 562 | /// 6. Determine availability of data directory and parse komodo.conf |
c52c4e5d | 563 | /// - Do not call GetDataDir(true) before this step finishes |
2102ab9f WL |
564 | if (!boost::filesystem::is_directory(GetDataDir(false))) |
565 | { | |
a409467e | 566 | QMessageBox::critical(0, QObject::tr("Bitcoin Core"), |
2102ab9f WL |
567 | QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); |
568 | return 1; | |
569 | } | |
4ae5e721 WL |
570 | try { |
571 | ReadConfigFile(mapArgs, mapMultiArgs); | |
27df4123 | 572 | } catch (const std::exception& e) { |
a409467e | 573 | QMessageBox::critical(0, QObject::tr("Bitcoin Core"), |
4ae5e721 WL |
574 | QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what())); |
575 | return false; | |
576 | } | |
2102ab9f | 577 | |
c52c4e5d WL |
578 | /// 7. Determine network (and switch to network specific options) |
579 | // - Do not call Params() before this step | |
580 | // - Do this after parsing the configuration file, as the network can be switched there | |
581 | // - QSettings() will use the new application name after this, resulting in network-specific settings | |
582 | // - Needs to be done before createOptionsModel | |
583 | ||
584 | // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) | |
585 | if (!SelectParamsFromCommandLine()) { | |
a409467e | 586 | QMessageBox::critical(0, QObject::tr("Bitcoin Core"), QObject::tr("Error: Invalid combination of -regtest and -testnet.")); |
c52c4e5d WL |
587 | return 1; |
588 | } | |
589 | #ifdef ENABLE_WALLET | |
590 | // Parse URIs on command line -- this can affect Params() | |
b82695b8 | 591 | PaymentServer::ipcParseCommandLine(argc, argv); |
c52c4e5d | 592 | #endif |
b82695b8 | 593 | |
6de50c3c WL |
594 | QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString()))); |
595 | assert(!networkStyle.isNull()); | |
c52c4e5d | 596 | // Allow for separate UI settings for testnets |
6de50c3c | 597 | QApplication::setApplicationName(networkStyle->getAppName()); |
c52c4e5d WL |
598 | // Re-initialize translations after changing application name (language in network-specific settings can be different) |
599 | initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); | |
600 | ||
b7f4b6d3 | 601 | #ifdef ENABLE_WALLET |
c52c4e5d | 602 | /// 8. URI IPC sending |
2102ab9f WL |
603 | // - Do this early as we don't want to bother initializing if we are just calling IPC |
604 | // - Do this *after* setting up the data directory, as the data directory hash is used in the name | |
605 | // of the server. | |
606 | // - Do this after creating app and setting up translations, so errors are | |
607 | // translated properly. | |
608 | if (PaymentServer::ipcSendCommandLine()) | |
609 | exit(0); | |
610 | ||
a73aa68b GA |
611 | // Start up the payment server early, too, so impatient users that click on |
612 | // bitcoin: links repeatedly have their payment requests routed to this process: | |
202d853b | 613 | app.createPaymentServer(); |
b7f4b6d3 | 614 | #endif |
a73aa68b | 615 | |
c52c4e5d | 616 | /// 9. Main GUI initialization |
3793fa09 WL |
617 | // Install global event filter that makes sure that long tooltips can be word-wrapped |
618 | app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); | |
e664c3d7 | 619 | #if QT_VERSION < 0x050000 |
d282c1fb | 620 | // Install qDebug() message handler to route to debug.log |
e664c3d7 PK |
621 | qInstallMsgHandler(DebugMessageHandler); |
622 | #else | |
d282c1fb PK |
623 | #if defined(Q_OS_WIN) |
624 | // Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION) | |
625 | qApp->installNativeEventFilter(new WinShutdownMonitor()); | |
626 | #endif | |
627 | // Install qDebug() message handler to route to debug.log | |
e664c3d7 PK |
628 | qInstallMessageHandler(DebugMessageHandler); |
629 | #endif | |
2102ab9f | 630 | // Load GUI settings from QSettings |
202d853b | 631 | app.createOptionsModel(); |
3f8cb2c5 | 632 | |
ab1b288f | 633 | // Subscribe to global signals from core |
ab1b288f | 634 | uiInterface.InitMessage.connect(InitMessage); |
ab1b288f | 635 | |
202d853b | 636 | if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false)) |
6de50c3c | 637 | app.createSplashScreen(networkStyle.data()); |
aaa1c3c4 | 638 | |
8e86dca2 WL |
639 | try |
640 | { | |
6de50c3c | 641 | app.createWindow(networkStyle.data()); |
202d853b | 642 | app.requestInitialize(); |
d282c1fb | 643 | #if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 |
4629f95b | 644 | WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("Bitcoin Core didn't yet exit safely..."), (HWND)app.getMainWinId()); |
d282c1fb | 645 | #endif |
202d853b WL |
646 | app.exec(); |
647 | app.requestShutdown(); | |
648 | app.exec(); | |
27df4123 | 649 | } catch (const std::exception& e) { |
202d853b WL |
650 | PrintExceptionContinue(&e, "Runaway exception"); |
651 | app.handleRunawayException(QString::fromStdString(strMiscWarning)); | |
18cab09a | 652 | } catch (...) { |
202d853b WL |
653 | PrintExceptionContinue(NULL, "Runaway exception"); |
654 | app.handleRunawayException(QString::fromStdString(strMiscWarning)); | |
18cab09a | 655 | } |
202d853b | 656 | return app.getReturnValue(); |
aaa1c3c4 | 657 | } |
24548467 | 658 | #endif // BITCOIN_QT_TEST |