X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLyX.cpp;h=04c1dd4f257e49e962cba22f24452b0f94dd96da;hb=2e32e2c1239fcb966f9eefc7926edf602b2ad9d8;hp=a732c7ee809e5fcd9a0b52429394e3133d6f96c9;hpb=489dca71cd99bbc78780fa40311a2eb042c0320e;p=lyx.git diff --git a/src/LyX.cpp b/src/LyX.cpp index a732c7ee80..04c1dd4f25 100644 --- a/src/LyX.cpp +++ b/src/LyX.cpp @@ -22,10 +22,12 @@ #include "Buffer.h" #include "BufferList.h" #include "CmdDef.h" +#include "CiteEnginesList.h" #include "ColorSet.h" #include "ConverterCache.h" #include "Converter.h" #include "CutAndPaste.h" +#include "DispatchResult.h" #include "EnchantChecker.h" #include "Encoding.h" #include "ErrorList.h" @@ -36,8 +38,6 @@ #include "Language.h" #include "LaTeXFonts.h" #include "LayoutFile.h" -#include "Lexer.h" -#include "LyX.h" #include "LyXAction.h" #include "LyXRC.h" #include "ModuleList.h" @@ -45,12 +45,12 @@ #include "Server.h" #include "ServerSocket.h" #include "Session.h" -#include "WordList.h" #include "frontends/alert.h" #include "frontends/Application.h" #include "support/ConsoleApplication.h" +#include "support/convert.h" #include "support/lassert.h" #include "support/debug.h" #include "support/environment.h" @@ -63,7 +63,6 @@ #include "support/Package.h" #include "support/unique_ptr.h" -#include #include #include #include @@ -72,6 +71,8 @@ #include #include +#include // For QT_VERSION + using namespace std; using namespace lyx::support; @@ -92,6 +93,19 @@ namespace os = support::os; bool use_gui = true; +// Report on the terminal about spawned commands. The default is false +// and can be changed with the option -v (--verbose). + +bool verbose = false; + + +// Do not treat the "missing glyphs" warning of fontspec as an error message. +// The default is false and can be changed with the option +// --ignore-error-message missing_glyphs +// This is used in automated testing. +bool ignore_missing_glyphs = false; + + // We default to open documents in an already running instance, provided that // the lyxpipe has been setup. This can be overridden either on the command // line or through preference settings. @@ -107,6 +121,14 @@ RunMode run_mode = PREFERRED; OverwriteFiles force_overwrite = UNSPECIFIED; +// Scale the GUI by this factor. This works whether we have a HiDpi screen +// or not and scales everything, also fonts. Can only be changed by setting +// the QT_SCALE_FACTOR environment variable before launching LyX and only +// works properly with Qt 5.6 or higher. + +double qt_scale_factor = 1.0; + + namespace { // Filled with the command line arguments "foo" of "-sysdir foo" or @@ -116,7 +138,7 @@ string cl_user_support; string geometryArg; -LyX * singleton_ = 0; +LyX * singleton_ = nullptr; void showFileError(string const & error) { @@ -125,12 +147,14 @@ void showFileError(string const & error) "Please check your installation."), from_utf8(error))); } -} // namespace anon +} // namespace /// The main application class private implementation. struct LyX::Impl { Impl() - : latexfonts_(0), spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0) + : latexfonts_(nullptr), spell_checker_(nullptr), + apple_spell_checker_(nullptr), aspell_checker_(nullptr), + enchant_checker_(nullptr), hunspell_checker_(nullptr) {} ~Impl() @@ -165,10 +189,15 @@ struct LyX::Impl { /// The file converters. Converters converters_; - - // The system converters copy after reading lyxrc.defaults. + /// The system converters after reading lyxrc.defaults. Converters system_converters_; + /// Global format information + Formats formats_; + /// The system formats after reading lyxrc.defaults. + Formats system_formats_; + + /// Movers movers_; /// @@ -202,7 +231,7 @@ public: argc_(argc), argv_(argv) { } - void doExec() + void doExec() override { int const exit_status = lyx_->execWithoutGui(argc_, argv_); exit(exit_status); @@ -220,15 +249,14 @@ frontend::Application * theApp() if (singleton_) return singleton_->pimpl_->application_.get(); else - return 0; + return nullptr; } LyX::~LyX() { delete pimpl_; - singleton_ = 0; - WordList::cleanupWordLists(); + singleton_ = nullptr; } @@ -290,6 +318,17 @@ int LyX::exec(int & argc, char * argv[]) // we need to parse for "-dbg" and "-help" easyParse(argc, argv); +#if QT_VERSION >= 0x050600 + // Check whether Qt will scale all GUI elements and accordingly + // set the scale factor so that to avoid blurred images and text + char const * const scale_factor = getenv("QT_SCALE_FACTOR"); + if (scale_factor) { + qt_scale_factor = convert(scale_factor); + if (qt_scale_factor < 1.0) + qt_scale_factor = 1.0; + } +#endif + try { init_package(os::utf8_argv(0), cl_system_support, cl_user_support); } catch (ExceptionMessage const & message) { @@ -354,14 +393,12 @@ int LyX::exec(int & argc, char * argv[]) FileName(package().temp_dir().absFileName() + "/lyxsocket"))); // Start the real execution loop. - if (!theServer().deferredLoadingToOtherInstance()) + if (!pimpl_->lyx_server_->deferredLoadingToOtherInstance()) exit_status = pimpl_->application_->exec(); else if (!pimpl_->files_to_load_.empty()) { - vector::const_iterator it = pimpl_->files_to_load_.begin(); - vector::const_iterator end = pimpl_->files_to_load_.end(); lyxerr << _("The following files could not be loaded:") << endl; - for (; it != end; ++it) - lyxerr << *it << endl; + for (auto const & f : pimpl_->files_to_load_) + lyxerr << f << endl; } prepareExit(); @@ -379,8 +416,12 @@ void LyX::prepareExit() // Write the index file of the converter cache ConverterCache::get().writeIndex(); - // close buffers first - pimpl_->buffer_list_.closeAll(); + // closing buffer may throw exceptions, but we ignore them since we + // are quitting. + try { + // close buffers first + pimpl_->buffer_list_.closeAll(); + } catch (ExceptionMessage const &) {} // register session changes and shutdown server and socket if (use_gui) { @@ -394,17 +435,16 @@ void LyX::prepareExit() // do any other cleanup procedures now if (package().temp_dir() != package().system_temp_dir()) { string const abs_tmpdir = package().temp_dir().absFileName(); - if (!contains(package().temp_dir().absFileName(), "lyx_tmpdir")) { + if (!contains(abs_tmpdir, "lyx_tmpdir")) { docstring const msg = bformat(_("%1$s does not appear like a LyX created temporary directory."), from_utf8(abs_tmpdir)); Alert::warning(_("Cannot remove temporary directory"), msg); } else { - LYXERR(Debug::INFO, "Deleting tmp dir " - << package().temp_dir().absFileName()); + LYXERR(Debug::INFO, "Deleting tmp dir " << abs_tmpdir); if (!package().temp_dir().destroyDirectory()) { LYXERR0(bformat(_("Unable to remove the temporary directory %1$s"), - from_utf8(package().temp_dir().absFileName()))); + from_utf8(abs_tmpdir))); } } } @@ -456,7 +496,7 @@ int LyX::init(int & argc, char * argv[]) if (first_start) { pimpl_->files_to_load_.push_back( - i18nLibFileSearch("examples", "splash.lyx").absFileName()); + i18nLibFileSearch("examples", "Welcome.lyx").absFileName()); } return EXIT_SUCCESS; @@ -472,7 +512,7 @@ int LyX::execWithoutGui(int & argc, char * argv[]) } // Used to keep track of which buffers were explicitly loaded by user request. - // This is necessary because master and child document buffers are loaded, even + // This is necessary because master and child document buffers are loaded, even // if they were not named on the command line. We do not want to dispatch to // those. vector command_line_buffers; @@ -541,10 +581,11 @@ void LyX::execCommands() { // The advantage of doing this here is that the event loop // is already started. So any need for interaction will be - // aknowledged. + // acknowledged. // if reconfiguration is needed. - if (LayoutFileList::get().empty()) { + const bool noLayouts = LayoutFileList::get().empty(); + if (noLayouts && os::hasPython()) { switch (Alert::prompt( _("No textclass is found"), _("LyX will only have minimal functionality because no textclasses " @@ -553,7 +594,8 @@ void LyX::execCommands() 0, 2, _("&Reconfigure"), _("&Without LaTeX"), - _("&Continue"))) + _("&Continue"), + _("&Exit LyX"))) { case 0: // regular reconfigure @@ -564,6 +606,25 @@ void LyX::execCommands() lyx::dispatch(FuncRequest(LFUN_RECONFIGURE, " --without-latex-config")); break; + case 3: + lyx::dispatch(FuncRequest(LFUN_LYX_QUIT, "")); + return; + default: + break; + } + } else if (noLayouts) { + switch (Alert::prompt( + _("No python is found"), + _("LyX will only have minimal functionality because no python interpreter " + "has been found. Consider installing python with your software manager " + "or from the python.org website."), + 0, 1, + _("&Continue"), + _("&Exit LyX"))) + { + case 1: + lyx::dispatch(FuncRequest(LFUN_LYX_QUIT, "")); + return; default: break; } @@ -731,7 +792,7 @@ namespace { return std::string(line, nameLen); } } -} +} // namespace void cleanDuplicateEnvVars() { @@ -866,6 +927,25 @@ bool LyX::init() if (package().build_support().empty()) prependEnvPath("PATH", package().binary_dir().absFileName()); #endif + { + // Add the directory containing the dt2dv and dv2dt executables to the path + FileName dtldir; + if (!package().build_support().empty()) { + // dtl executables should be in the same dir ar tex2lyx + dtldir = package().binary_dir(); + } + else { + dtldir = FileName(addName(package().system_support().absFileName(), "extratools")); + } +#if defined(_WIN32) + string dtlexe = "dt2dv.exe"; +#else + string dtlexe = "dt2dv"; +#endif + FileName const dt2dv = FileName(addName(dtldir.absFileName(), dtlexe)); + if (dt2dv.exists()) + prependEnvPath("PATH", dtldir.absFileName()); + } if (!lyxrc.path_prefix.empty()) prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix)); @@ -903,13 +983,13 @@ bool LyX::init() return false; // Query the OS to know what formats are viewed natively - formats.setAutoOpen(); + theFormats().setAutoOpen(); // Read lyxrc.dist again to be able to override viewer auto-detection. readRcFile("lyxrc.dist"); system_lyxrc = lyxrc; - system_formats = formats; + theSystemFormats() = theFormats(); pimpl_->system_converters_ = pimpl_->converters_; pimpl_->system_movers_ = pimpl_->movers_; system_lcolor = lcolor; @@ -929,8 +1009,10 @@ bool LyX::init() LYXERR(Debug::INIT, "Reading layouts..."); // Load the layouts LayoutFileList::get().read(); - //...and the modules + //... the modules theModuleList.read(); + //... and the cite engines + theCiteEnginesList.read(); // read keymap and ui files in batch mode as well // because InsetInfo needs to know these to produce @@ -944,7 +1026,7 @@ bool LyX::init() pimpl_->toplevel_keymap_.read("site"); pimpl_->toplevel_keymap_.read(lyxrc.bind_file); // load user bind file user.bind - pimpl_->toplevel_keymap_.read("user", 0, KeyMap::MissingOK); + pimpl_->toplevel_keymap_.read("user", nullptr, KeyMap::MissingOK); if (lyxerr.debugging(Debug::LYXRC)) lyxrc.print(); @@ -1014,7 +1096,9 @@ bool LyX::queryUserLyXDir(bool explicit_userdir) return configFileNeedsUpdate("lyxrc.defaults") || configFileNeedsUpdate("lyxmodules.lst") || configFileNeedsUpdate("textclass.lst") - || configFileNeedsUpdate("packages.lst"); + || configFileNeedsUpdate("packages.lst") + || configFileNeedsUpdate("lyxciteengines.lst") + || configFileNeedsUpdate("xtemplates.lst"); } first_start = !explicit_userdir; @@ -1040,7 +1124,7 @@ bool LyX::queryUserLyXDir(bool explicit_userdir) if (!sup.createDirectory(0755)) { // Failed, so let's exit. - lyxerr << to_utf8(_("Failed to create directory. Exiting.")) + lyxerr << to_utf8(_("Failed to create directory. Perhaps wrong -userdir command-line option?\nExiting.")) << endl; earlyExit(EXIT_FAILURE); } @@ -1117,10 +1201,15 @@ int parse_dbg(string const & arg, string const &, string &) Debug::showTags(cout); exit(0); } - lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl; - - lyxerr.setLevel(Debug::value(arg)); - Debug::showLevel(lyxerr, lyxerr.level()); + string bad = Debug::badValue(arg); + if (bad.empty()) { + lyxerr.setLevel(Debug::value(arg)); + Debug::showLevel(lyxerr, lyxerr.level()); + } else { + cout << to_utf8(bformat(_("Bad debug value `%1$s'. Exiting."), + from_utf8(bad))) << endl; + exit(1); + } return 1; } @@ -1143,7 +1232,8 @@ int parse_help(string const &, string const &, string &) " where fmt is the export format of choice. Look in\n" " Tools->Preferences->File Handling->File Formats->Short Name\n" " to see which parameter (which differs from the format name\n" - " in the File->Export menu) should be passed.\n" + " in the File->Export menu) should be passed. To export to\n" + " the document's default output format, use 'default'.\n" " Note that the order of -e and -x switches matters.\n" "\t-E [--export-to] fmt filename\n" " where fmt is the export format of choice (see --export),\n" @@ -1156,11 +1246,17 @@ int parse_help(string const &, string const &, string &) " specifying whether all files, main file only, or no files,\n" " respectively, are to be overwritten during a batch export.\n" " Anything else is equivalent to `all', but is not consumed.\n" + "\t--ignore-error-message which\n" + " allows you to ignore specific LaTeX error messages.\n" + " Do not use for final documents! Currently supported values:\n" + " * missing_glyphs: Fontspec `missing glyphs' error.\n" "\t-n [--no-remote]\n" " open documents in a new instance\n" "\t-r [--remote]\n" " open documents in an already running instance\n" " (a working lyxpipe is needed)\n" + "\t-v [--verbose]\n" + " report on terminal about spawned commands.\n" "\t-batch execute commands without launching GUI and exit.\n" "\t-version summarize version and build info\n" "Check the LyX man page for more details.")) << endl; @@ -1295,6 +1391,23 @@ int parse_remote(string const &, string const &, string &) } +int parse_verbose(string const &, string const &, string &) +{ + verbose = true; + return 0; +} + + +int parse_ignore_error_message(string const & arg1, string const &, string &) +{ + if (arg1 == "missing_glyphs") { + ignore_missing_glyphs = true; + return 1; + } + return 0; +} + + int parse_force(string const & arg, string const &, string &) { if (arg == "all") { @@ -1312,7 +1425,7 @@ int parse_force(string const & arg, string const &, string &) } -} // namespace anon +} // namespace void LyX::easyParse(int & argc, char * argv[]) @@ -1342,6 +1455,9 @@ void LyX::easyParse(int & argc, char * argv[]) cmdmap["--no-remote"] = parse_noremote; cmdmap["-r"] = parse_remote; cmdmap["--remote"] = parse_remote; + cmdmap["-v"] = parse_verbose; + cmdmap["--verbose"] = parse_verbose; + cmdmap["--ignore-error-message"] = parse_ignore_error_message; for (int i = 1; i < argc; ++i) { map::const_iterator it @@ -1434,17 +1550,31 @@ KeyMap & theTopLevelKeymap() } +Formats & theFormats() +{ + LAPPERR(singleton_); + return singleton_->pimpl_->formats_; +} + + +Formats & theSystemFormats() +{ + LAPPERR(singleton_); + return singleton_->pimpl_->system_formats_; +} + + Converters & theConverters() { LAPPERR(singleton_); - return singleton_->pimpl_->converters_; + return singleton_->pimpl_->converters_; } Converters & theSystemConverters() { LAPPERR(singleton_); - return singleton_->pimpl_->system_converters_; + return singleton_->pimpl_->system_converters_; } @@ -1532,7 +1662,7 @@ void setSpellChecker() singleton_->pimpl_->apple_spell_checker_ = new AppleSpellChecker; singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->apple_spell_checker_; #else - singleton_->pimpl_->spell_checker_ = 0; + singleton_->pimpl_->spell_checker_ = nullptr; #endif } else if (lyxrc.spellchecker == "aspell") { #if defined(USE_ASPELL) @@ -1540,7 +1670,7 @@ void setSpellChecker() singleton_->pimpl_->aspell_checker_ = new AspellChecker; singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->aspell_checker_; #else - singleton_->pimpl_->spell_checker_ = 0; + singleton_->pimpl_->spell_checker_ = nullptr; #endif } else if (lyxrc.spellchecker == "enchant") { #if defined(USE_ENCHANT) @@ -1548,7 +1678,7 @@ void setSpellChecker() singleton_->pimpl_->enchant_checker_ = new EnchantChecker; singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_; #else - singleton_->pimpl_->spell_checker_ = 0; + singleton_->pimpl_->spell_checker_ = nullptr; #endif } else if (lyxrc.spellchecker == "hunspell") { #if defined(USE_HUNSPELL) @@ -1556,10 +1686,10 @@ void setSpellChecker() singleton_->pimpl_->hunspell_checker_ = new HunspellChecker; singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->hunspell_checker_; #else - singleton_->pimpl_->spell_checker_ = 0; + singleton_->pimpl_->spell_checker_ = nullptr; #endif } else { - singleton_->pimpl_->spell_checker_ = 0; + singleton_->pimpl_->spell_checker_ = nullptr; } if (singleton_->pimpl_->spell_checker_) { singleton_->pimpl_->spell_checker_->changeNumber(speller_change_number);