mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-30 17:24:08 +00:00
437 lines
11 KiB
C++
437 lines
11 KiB
C++
/* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
|
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
|
|
|
#include <stdio.h>
|
|
#include <QIcon>
|
|
#include "gdappstyle.hh"
|
|
#include "mainwindow.hh"
|
|
#include "config.hh"
|
|
#include "article_netmgr.hh"
|
|
#include <QWebEngineProfile>
|
|
#include "processwrapper.hh"
|
|
#include "hotkeywrapper.hh"
|
|
#ifdef HAVE_X11
|
|
#include <fixx11h.h>
|
|
#endif
|
|
|
|
#if defined( Q_OS_UNIX )
|
|
#include <clocale>
|
|
#endif
|
|
|
|
//#define __DO_DEBUG
|
|
|
|
#define LOG_TO_FILE_KEY "--log-to-file"
|
|
|
|
#ifdef Q_OS_WIN32
|
|
#include <QtCore/qt_windows.h>
|
|
#endif
|
|
|
|
#ifdef __DO_DEBUG
|
|
#include <sys/resource.h>
|
|
#endif
|
|
|
|
#include "termination.hh"
|
|
#include "atomic_rename.hh"
|
|
#include <QtWebEngineCore/QWebEngineUrlScheme>
|
|
#include <QMessageBox>
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
#include <QByteArray>
|
|
#include <QString>
|
|
|
|
#include "gddebug.hh"
|
|
|
|
void gdMessageHandler( QtMsgType type, const QMessageLogContext &context, const QString &mess )
|
|
{
|
|
Q_UNUSED( context );
|
|
QString message( mess );
|
|
QByteArray msg = message.toUtf8().constData();
|
|
|
|
switch (type) {
|
|
|
|
case QtDebugMsg:
|
|
if( logFilePtr && logFilePtr->isOpen() )
|
|
message.insert( 0, "Debug: " );
|
|
else
|
|
fprintf(stderr, "Debug: %s\n", msg.constData());
|
|
break;
|
|
|
|
case QtWarningMsg:
|
|
if( logFilePtr && logFilePtr->isOpen() )
|
|
message.insert( 0, "Warning: " );
|
|
else
|
|
fprintf(stderr, "Warning: %s\n", msg.constData());
|
|
break;
|
|
|
|
case QtCriticalMsg:
|
|
if( logFilePtr && logFilePtr->isOpen() )
|
|
message.insert( 0, "Critical: " );
|
|
else
|
|
fprintf(stderr, "Critical: %s\n", msg.constData());
|
|
break;
|
|
|
|
case QtFatalMsg:
|
|
if( logFilePtr && logFilePtr->isOpen() )
|
|
{
|
|
logFilePtr->write( "Fatal: " );
|
|
logFilePtr->write( msg );
|
|
logFilePtr->flush();
|
|
}
|
|
else
|
|
fprintf(stderr, "Fatal: %s\n", msg.constData());
|
|
abort();
|
|
case QtInfoMsg:
|
|
if( logFilePtr && logFilePtr->isOpen() )
|
|
message.insert( 0, "Info: " );
|
|
else
|
|
fprintf(stderr, "Info: %s\n", msg.constData());
|
|
break;
|
|
}
|
|
|
|
if( logFilePtr && logFilePtr->isOpen() )
|
|
{
|
|
message.insert( 0, QDateTime::currentDateTime().toString( "yyyy-MM-dd HH:mm:ss.zzz " ) );
|
|
message.append( "\n" );
|
|
logFilePtr->write( message.toUtf8() );
|
|
logFilePtr->flush();
|
|
}
|
|
}
|
|
|
|
class GDCommandLine
|
|
{
|
|
bool crashReport, logFile;
|
|
QString word, groupName, popupGroupName, errFileName;
|
|
QVector< QString > arguments;
|
|
public:
|
|
GDCommandLine( int argc, char **argv );
|
|
|
|
inline bool needCrashReport()
|
|
{ return crashReport; }
|
|
|
|
inline QString errorFileName()
|
|
{ return errFileName; }
|
|
|
|
inline bool needSetGroup()
|
|
{ return !groupName.isEmpty(); }
|
|
|
|
inline QString getGroupName()
|
|
{ return groupName; }
|
|
|
|
inline bool needSetPopupGroup()
|
|
{ return !popupGroupName.isEmpty(); }
|
|
|
|
inline QString getPopupGroupName()
|
|
{ return popupGroupName; }
|
|
|
|
inline bool needLogFile()
|
|
{ return logFile; }
|
|
|
|
inline bool needTranslateWord()
|
|
{ return !word.isEmpty(); }
|
|
|
|
inline QString wordToTranslate()
|
|
{ return word; }
|
|
};
|
|
|
|
GDCommandLine::GDCommandLine( int argc, char **argv ):
|
|
crashReport( false ),
|
|
logFile( false )
|
|
{
|
|
if( argc > 1 )
|
|
{
|
|
#ifdef Q_OS_WIN32
|
|
(void) argv;
|
|
int num;
|
|
LPWSTR *pstr = CommandLineToArgvW( GetCommandLineW(), &num );
|
|
if( pstr && num > 1 )
|
|
{
|
|
for( int i = 1; i < num; i++ )
|
|
arguments.push_back( QString::fromWCharArray( pstr[ i ] ) );
|
|
}
|
|
#else
|
|
for( int i = 1; i < argc; i++ )
|
|
arguments.push_back( QString::fromLocal8Bit( argv[ i ] ) );
|
|
#endif
|
|
// Parse command line
|
|
for( int i = 0; i < arguments.size(); i++ )
|
|
{
|
|
if( arguments[ i ].compare( "--show-error-file" ) == 0 )
|
|
{
|
|
if( i < arguments.size() - 1 )
|
|
{
|
|
errFileName = arguments[ ++i ];
|
|
crashReport = true;
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
if( arguments[ i ].compare( "--log-to-file" ) == 0 )
|
|
{
|
|
logFile = true;
|
|
continue;
|
|
}
|
|
else
|
|
if( arguments[ i ].startsWith( "--group-name=" ) )
|
|
{
|
|
groupName = arguments[ i ].mid( arguments[ i ].indexOf( '=' ) + 1 );
|
|
continue;
|
|
}
|
|
else
|
|
if( arguments[ i ].startsWith( "--popup-group-name=" ) )
|
|
{
|
|
popupGroupName = arguments[ i ].mid( arguments[ i ].indexOf( '=' ) + 1 );
|
|
continue;
|
|
}
|
|
else
|
|
word = arguments[ i ];
|
|
}
|
|
}
|
|
}
|
|
|
|
class LogFilePtrGuard
|
|
{
|
|
QFile logFile;
|
|
Q_DISABLE_COPY( LogFilePtrGuard )
|
|
public:
|
|
LogFilePtrGuard() { logFilePtr = &logFile; }
|
|
~LogFilePtrGuard() { logFilePtr = 0; }
|
|
};
|
|
|
|
int main( int argc, char ** argv )
|
|
{
|
|
#ifdef Q_OS_UNIX
|
|
// GoldenDict use lots of X11 functions and it currently cannot work
|
|
// natively on Wayland. This workaround will force GoldenDict to use
|
|
// XWayland.
|
|
char * xdg_envc = getenv("XDG_SESSION_TYPE");
|
|
QString xdg_session = xdg_envc ? QString::fromLatin1(xdg_envc) : QString();
|
|
if (!QString::compare(xdg_session, QString("wayland"), Qt::CaseInsensitive))
|
|
{
|
|
setenv("QT_QPA_PLATFORM", "xcb", 1);
|
|
}
|
|
#endif
|
|
#ifdef Q_OS_MAC
|
|
setenv("LANG", "en_US.UTF-8", 1);
|
|
|
|
#endif
|
|
|
|
#if defined( Q_OS_UNIX )
|
|
setlocale( LC_ALL, "" ); // use correct char set mapping
|
|
#endif
|
|
|
|
GDCommandLine gdcl( argc, argv );
|
|
|
|
if ( gdcl.needCrashReport() )
|
|
{
|
|
// The program has crashed -- show a message about it
|
|
|
|
QApplication app( argc, argv );
|
|
|
|
QFile errFile( gdcl.errorFileName() );
|
|
|
|
QString errorText;
|
|
|
|
if ( errFile.open( QFile::ReadOnly ) )
|
|
errorText = QString::fromUtf8( errFile.readAll() );
|
|
|
|
errorText += "\n" + QString( "This information is located in file %1, "
|
|
"which will be removed once you close this dialog.").arg( errFile.fileName() );
|
|
|
|
QMessageBox::critical( 0, "GoldenDict has crashed", errorText );
|
|
|
|
errFile.remove();
|
|
|
|
return 0;
|
|
}
|
|
|
|
installTerminationHandler();
|
|
|
|
#ifdef __DO_DEBUG
|
|
{
|
|
rlimit limit;
|
|
|
|
memset( &limit, 0, sizeof( limit ) );
|
|
limit.rlim_cur = RLIM_INFINITY;
|
|
limit.rlim_max = RLIM_INFINITY;
|
|
setrlimit( RLIMIT_CORE, &limit );
|
|
}
|
|
#endif
|
|
|
|
#ifdef __WIN32
|
|
|
|
// Under Windows, increase the amount of fopen()-able file descriptors from
|
|
// the default 512 up to 2048.
|
|
_setmaxstdio( 2048 );
|
|
|
|
#endif
|
|
|
|
QStringList localSchemes={"gdlookup","gdau","gico","qrcx","bres","bword","gdprg","gdvideo","gdpicture","gdtts"};
|
|
|
|
for (int i = 0; i < localSchemes.size(); ++i)
|
|
{
|
|
QString localScheme=localSchemes.at(i);
|
|
QWebEngineUrlScheme webUiScheme(localScheme.toLatin1());
|
|
webUiScheme.setFlags(QWebEngineUrlScheme::SecureScheme |
|
|
QWebEngineUrlScheme::LocalScheme |
|
|
QWebEngineUrlScheme::LocalAccessAllowed|
|
|
QWebEngineUrlScheme::CorsEnabled);
|
|
QWebEngineUrlScheme::registerScheme(webUiScheme);
|
|
}
|
|
|
|
//high dpi screen support
|
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
|
qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
|
|
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
|
|
|
QHotkeyApplication app( "GoldenDict", argc, argv );
|
|
LogFilePtrGuard logFilePtrGuard;
|
|
|
|
if ( app.isRunning() )
|
|
{
|
|
bool wasMessage = false;
|
|
|
|
if( gdcl.needSetGroup() )
|
|
{
|
|
app.sendMessage( QString( "setGroup: " ) + gdcl.getGroupName() );
|
|
wasMessage = true;
|
|
}
|
|
|
|
if( gdcl.needSetPopupGroup() )
|
|
{
|
|
app.sendMessage( QString( "setPopupGroup: " ) + gdcl.getPopupGroupName() );
|
|
wasMessage = true;
|
|
}
|
|
|
|
if( gdcl.needTranslateWord() )
|
|
{
|
|
app.sendMessage( QString( "translateWord: " ) + gdcl.wordToTranslate() );
|
|
wasMessage = true;
|
|
}
|
|
|
|
if( !wasMessage )
|
|
app.sendMessage("bringToFront");
|
|
|
|
return 0; // Another instance is running
|
|
}
|
|
|
|
app.setApplicationName( "GoldenDict" );
|
|
app.setOrganizationDomain( "http://goldendict.org/" );
|
|
app.setStyle(new GdAppStyle);
|
|
|
|
#ifndef Q_OS_MAC
|
|
app.setWindowIcon( QIcon( ":/icons/programicon.png" ) );
|
|
#endif
|
|
|
|
#ifdef MAKE_CHINESE_CONVERSION_SUPPORT
|
|
// OpenCC needs to load it's data files by relative path on Windows and OS X
|
|
QDir::setCurrent( Config::getProgramDataDir() );
|
|
#endif
|
|
|
|
// Load translations for system locale
|
|
QString localeName = QLocale::system().name();
|
|
|
|
Config::Class cfg;
|
|
for( ; ; )
|
|
{
|
|
try
|
|
{
|
|
cfg = Config::load();
|
|
}
|
|
catch( Config::exError & )
|
|
{
|
|
QMessageBox mb( QMessageBox::Warning, app.applicationName(),
|
|
app.translate( "Main", "Error in configuration file. Continue with default settings?" ),
|
|
QMessageBox::Yes | QMessageBox::No );
|
|
mb.exec();
|
|
if( mb.result() != QMessageBox::Yes )
|
|
return -1;
|
|
|
|
QString configFile = Config::getConfigFileName();
|
|
renameAtomically( configFile, configFile + ".bad" );
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if( gdcl.needLogFile() )
|
|
{
|
|
// Open log file
|
|
logFilePtr->setFileName( Config::getConfigDir() + "gd_log.txt" );
|
|
logFilePtr->remove();
|
|
logFilePtr->open( QFile::ReadWrite );
|
|
|
|
// Write UTF-8 BOM
|
|
QByteArray line;
|
|
line.append( 0xEF ).append( 0xBB ).append( 0xBF );
|
|
logFilePtr->write( line );
|
|
|
|
// Install message handler
|
|
qInstallMessageHandler( gdMessageHandler );
|
|
}
|
|
|
|
if ( Config::isPortableVersion() )
|
|
{
|
|
// For portable version, hardcode some settings
|
|
|
|
cfg.paths.clear();
|
|
cfg.paths.push_back( Config::Path( Config::getPortableVersionDictionaryDir(), true ) );
|
|
cfg.soundDirs.clear();
|
|
cfg.hunspell.dictionariesPath = Config::getPortableVersionMorphoDir();
|
|
}
|
|
|
|
// Reload translations for user selected locale is nesessary
|
|
QTranslator qtTranslator;
|
|
QTranslator translator;
|
|
if( !cfg.preferences.interfaceLanguage.isEmpty() && localeName != cfg.preferences.interfaceLanguage )
|
|
{
|
|
localeName = cfg.preferences.interfaceLanguage;
|
|
}
|
|
|
|
QLocale locale( localeName );
|
|
QLocale::setDefault( locale );
|
|
if( !qtTranslator.load( "qt_" + localeName, Config::getLocDir() ) )
|
|
{
|
|
qtTranslator.load( "qt_" + localeName, QLibraryInfo::location( QLibraryInfo::TranslationsPath ) );
|
|
app.installTranslator( &qtTranslator );
|
|
}
|
|
|
|
translator.load( Config::getLocDir() + "/" + localeName );
|
|
app.installTranslator( &translator );
|
|
|
|
QTranslator webengineTs;
|
|
if( webengineTs.load( "qtwebengine_" + localeName, Config::getLocDir() ) )
|
|
{
|
|
app.installTranslator( &webengineTs );
|
|
}
|
|
|
|
// Prevent app from quitting spontaneously when it works with scan popup
|
|
// and with the main window closed.
|
|
app.setQuitOnLastWindowClosed( false );
|
|
|
|
MainWindow m( cfg );
|
|
|
|
app.addDataCommiter( m );
|
|
|
|
QObject::connect( &app, SIGNAL(messageReceived(QString)),
|
|
&m, SLOT(messageFromAnotherInstanceReceived(QString)));
|
|
|
|
if( gdcl.needSetGroup() )
|
|
m.setGroupByName( gdcl.getGroupName(), true );
|
|
|
|
if( gdcl.needSetPopupGroup() )
|
|
m.setGroupByName( gdcl.getPopupGroupName(), false );
|
|
|
|
if( gdcl.needTranslateWord() )
|
|
m.wordReceived( gdcl.wordToTranslate() );
|
|
|
|
int r = app.exec();
|
|
|
|
app.removeDataCommiter( m );
|
|
|
|
if( logFilePtr->isOpen() )
|
|
logFilePtr->close();
|
|
|
|
return r;
|
|
}
|