X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt%2FGuiApplication.cpp;h=ed201301a7de9784091ab41560d8e4ead8e4923a;hb=ae56fb617184114329d1e5b9b5fbd6e2bc112231;hp=2c87ad10a2aecb6210b105bb8e1c7df58de1b3c0;hpb=d25c10ed81e63263392fcd72727ea3907e61c8e4;p=features.git diff --git a/src/frontends/qt/GuiApplication.cpp b/src/frontends/qt/GuiApplication.cpp index 2c87ad10a2..ed201301a7 100644 --- a/src/frontends/qt/GuiApplication.cpp +++ b/src/frontends/qt/GuiApplication.cpp @@ -59,9 +59,11 @@ #include "insets/InsetText.h" +#include "support/checksum.h" #include "support/convert.h" #include "support/debug.h" #include "support/ExceptionMessage.h" +#include "support/environment.h" #include "support/FileName.h" #include "support/filetools.h" #include "support/ForkedCalls.h" @@ -85,9 +87,11 @@ #include #include +#include #include +#if QT_VERSION < 0x060000 #include -#include +#endif #include #include #include @@ -102,7 +106,11 @@ #include #include #include +#include #include +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) +#include +#endif #include #include #include @@ -132,9 +140,19 @@ #if (QT_VERSION < 0x050000) #include #define QWINDOWSMIME QWindowsMime +#define QVARIANTTYPE QVariant::Type +#elif (QT_VERSION >= 0x060000) +#include +#include +#include +#define QWINDOWSMIME QWindowsMime +#define QVARIANTTYPE QMetaType +using QWindowsMime = QNativeInterface::Private::QWindowsMime; +using QWindowsApplication = QNativeInterface::Private::QWindowsApplication; #else #include #define QWINDOWSMIME QWinMime +#define QVARIANTTYPE QVariant::Type #endif #ifdef Q_CC_GNU #include @@ -143,12 +161,10 @@ #endif #endif -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && (QT_VERSION < 0x060000) #include #endif // Q_OS_MAC -#include - #include #include #include @@ -180,6 +196,24 @@ frontend::Application * createApplication(int & argc, char * argv[]) AllowSetForegroundWindow(ASFW_ANY); #endif + +// Setup high DPI handling. This is a bit complicated, but will be default in Qt6. +// macOS does it by itself. +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && !defined(Q_OS_MAC) +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + // Attribute Qt::AA_EnableHighDpiScaling must be set before QCoreApplication is created + if (getEnv("QT_ENABLE_HIGHDPI_SCALING").empty() + && getEnv("QT_AUTO_SCREEN_SCALE_FACTOR").empty()) + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); +#endif + +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + // HighDPI scale factor policy must be set before QGuiApplication is created + if (getEnv("QT_SCALE_FACTOR_ROUNDING_POLICY").empty()) + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); +#endif +#endif + frontend::GuiApplication * guiApp = new frontend::GuiApplication(argc, argv); // I'd rather do that in the constructor, but I do not think that // the palette is accessible there. @@ -477,9 +511,10 @@ QString themeIconName(QString const & action) } -// the returned bool is true if the icon needs to be flipped -pair iconName(FuncRequest const & f, bool unknown, bool rtl) +IconInfo iconInfo(FuncRequest const & f, bool unknown, bool rtl) { + IconInfo res; + QStringList names; QString lfunname = toqstr(lyxaction.getActionName(f.action())); @@ -489,6 +524,8 @@ pair iconName(FuncRequest const & f, bool unknown, bool rtl) name.replace(' ', '_'); name.replace(';', '_'); name.replace('\\', "backslash"); + // avoid duplication for these + name.replace("dialog-toggle", "dialog-show"); names << name; // then special default icon for some lfuns @@ -526,11 +563,11 @@ pair iconName(FuncRequest const & f, bool unknown, bool rtl) if (unknown) names << "unknown"; - search_mode const mode = theGuiApp()->imageSearchMode(); + search_mode const mode = theGuiApp() ? theGuiApp()->imageSearchMode() : support::must_exist; // The folders where icons are searched for QStringList imagedirs; - imagedirs << "images/" << "images/ipa/"; - // This is used to search for rtl version of icons which have the +rrtl suffix. + imagedirs << "images/ipa/" << "images/"; + // This is used to search for rtl version of icons which have the +rtl suffix. QStringList suffixes; if (rtl) suffixes << "+rtl"; @@ -541,16 +578,60 @@ pair iconName(FuncRequest const & f, bool unknown, bool rtl) for (QString const & suffix : suffixes) { QString id = imagedir; FileName fname = imageLibFileSearch(id, name + suffix, "svgz,png", mode); - if (fname.exists()) - return make_pair(toqstr(fname.absFileName()), - rtl && suffix.isEmpty()); + if (fname.exists()) { + docstring const fpath = fname.absoluteFilePath(); + res.filepath = toqstr(fname.absFileName()); + // these icons are subject to inversion in dark mode + res.invert = (contains(fpath, from_ascii("math")) || contains(fpath, from_ascii("ert-insert")) + || suffixIs(fname.onlyPath().absoluteFilePath(), from_ascii("ipa"))); + res.swap = rtl && suffix.isEmpty(); + return res; + } } LYXERR(Debug::GUI, "Cannot find icon for command \"" << lyxaction.getActionName(f.action()) << '(' << to_utf8(f.argument()) << ")\""); - return make_pair(QString(), false); + return res; +} + + +QPixmap prepareForDarkMode(QPixmap pixmap) +{ + QPalette palette = QPalette(); + QColor text_color = palette.color(QPalette::Active, QPalette::WindowText); + QColor bg_color = palette.color(QPalette::Active, QPalette::Window); + + // guess whether we are in dark mode + if (text_color.black() > bg_color.black()) + // not in dark mode, do nothing + return pixmap; + + // create a layer with black text turned to QPalette::WindowText + QPixmap black_overlay(pixmap.size()); + black_overlay.fill(text_color); + black_overlay.setMask(pixmap.createMaskFromColor(Qt::black, Qt::MaskOutColor)); + + // create a layer with blue text turned to lighter blue + QPixmap blue_overlay(pixmap.size()); + QColor math_blue(0, 0, 255); + blue_overlay.fill(guiApp->colorCache().get(Color(Color_math))); + blue_overlay.setMask(pixmap.createMaskFromColor(math_blue, Qt::MaskOutColor)); + + // create a layer with ("latex") red text turned to lighter red + QPixmap red_overlay(pixmap.size()); + QColor math_red(128, 0, 0); + red_overlay.fill(guiApp->colorCache().get(Color(Color_latex))); + red_overlay.setMask(pixmap.createMaskFromColor(math_red, Qt::MaskOutColor)); + + // put layers on top of existing pixmap + QPainter painter(&pixmap); + painter.drawPixmap(pixmap.rect(), black_overlay); + painter.drawPixmap(pixmap.rect(), blue_overlay); + painter.drawPixmap(pixmap.rect(), red_overlay); + + return pixmap; } @@ -561,8 +642,12 @@ QPixmap getPixmap(QString const & path, QString const & name, QString const & ex QString fpath = toqstr(fname.absFileName()); QPixmap pixmap = QPixmap(); - if (pixmap.load(fpath)) + if (pixmap.load(fpath)) { + if (fpath.contains("math") || fpath.contains("ipa") + || fpath.contains("bullets")) + return prepareForDarkMode(pixmap); return pixmap; + } bool const list = ext.contains(","); LYXERR(Debug::GUI, "Cannot load pixmap \"" @@ -590,20 +675,21 @@ QIcon getIcon(FuncRequest const & f, bool unknown, bool rtl) } #endif - QString icon; - bool flip; - tie(icon, flip) = iconName(f, unknown, rtl); - if (icon.isEmpty()) + IconInfo icondata = iconInfo(f, unknown, rtl); + if (icondata.filepath.isEmpty()) return QIcon(); //LYXERR(Debug::GUI, "Found icon: " << icon); QPixmap pixmap = QPixmap(); - if (!pixmap.load(icon)) { - LYXERR0("Cannot load icon " << icon << "."); + if (!pixmap.load(icondata.filepath)) { + LYXERR0("Cannot load icon " << icondata.filepath << "."); return QIcon(); } - if (flip) + if (icondata.invert) + pixmap = prepareForDarkMode(pixmap); + + if (icondata.swap) return QIcon(pixmap.transformed(QTransform().scale(-1, 1))); else return QIcon(pixmap); @@ -640,7 +726,7 @@ public: QString translate(const char * /* context */, const char *sourceText, #if QT_VERSION >= 0x050000 - const char * /* disambiguation */ = 0, int /* n */ = -1) const override + const char * /* disambiguation */ = nullptr, int /* n */ = -1) const override #else const char * /*comment*/ = 0) const override #endif @@ -674,7 +760,7 @@ public: // //////////////////////////////////////////////////////////////////////// -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && (QT_VERSION < 0x060000) // QMacPasteboardMimeGraphics can only be compiled on Mac. class QMacPasteboardMimeGraphics : public QMacPasteboardMime @@ -781,7 +867,7 @@ public: } QVariant convertToMime(QString const & mimetype, IDataObject * pDataObj, - QVariant::Type /*preferredType*/) const override + QVARIANTTYPE /*preferredType*/) const override { QByteArray data; if (!canConvertToMime(mimetype, pDataObj)) @@ -896,16 +982,33 @@ struct GuiApplication::Private { Private(): language_model_(nullptr), meta_fake_bit(NoModifier), global_menubar_(nullptr) + #if (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)) + , last_state_(Qt::ApplicationInactive) + #endif { #if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400) #if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) /// WMF Mime handler for Windows clipboard. wmf_mime_ = new QWindowsMimeMetafile; + #if (QT_VERSION >= 0x060000) + win_app_ = dynamic_cast + (QGuiApplicationPrivate::platformIntegration()); + win_app_->registerMime(wmf_mime_); + #endif #endif #endif initKeySequences(&theTopLevelKeymap()); } + #if (QT_VERSION >= 0x060000) + #if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) + ~Private() + { + win_app_->unregisterMime(wmf_mime_); + } + #endif + #endif + void initKeySequences(KeyMap * kb) { keyseq = KeySequence(kb, kb); @@ -962,8 +1065,12 @@ struct GuiApplication::Private /// Only used on mac. QMenuBar * global_menubar_; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)) + /// Holds previous application state on Mac + Qt::ApplicationState last_state_; +#endif -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && (QT_VERSION < 0x060000) /// Linkback mime handler for MacOSX. QMacPasteboardMimeGraphics mac_pasteboard_mime_; #endif @@ -972,6 +1079,9 @@ struct GuiApplication::Private #if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) /// WMF Mime handler for Windows clipboard. QWindowsMimeMetafile * wmf_mime_; +#if (QT_VERSION >= 0x060000) + QWindowsApplication * win_app_; +#endif #endif #endif @@ -999,7 +1109,7 @@ GuiApplication::GuiApplication(int & argc, char ** argv) QCoreApplication::setOrganizationName(app_name); QCoreApplication::setOrganizationDomain("lyx.org"); QCoreApplication::setApplicationName(lyx_package); -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= 0x050000 && QT_VERSION < 0x060000 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif @@ -1007,7 +1117,11 @@ GuiApplication::GuiApplication(int & argc, char ** argv) setDesktopFileName(lyx_package); #endif +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + QRandomGenerator(QDateTime::currentDateTime().toSecsSinceEpoch()); +#else qsrand(QDateTime::currentDateTime().toTime_t()); +#endif // Install LyX translator for missing Qt translations installTranslator(&d->gui_trans_); @@ -1034,6 +1148,10 @@ GuiApplication::GuiApplication(int & argc, char ** argv) setupApplescript(); appleCleanupEditMenu(); appleCleanupViewMenu(); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)) + connect(this, SIGNAL(applicationStateChanged(Qt::ApplicationState)), + this, SLOT(onApplicationStateChanged(Qt::ApplicationState))); +#endif #endif #if defined(Q_WS_X11) || defined(QPA_XCB) @@ -1089,6 +1207,29 @@ GuiApplication * theGuiApp() } +#if QT_VERSION < 0x050000 +// Emulate platformName() for Qt4 + +// FIXME: when ditching this method, remove all tests +// platformName() == "qt4x11" +// in the code +QString GuiApplication::platformName() const +{ +# if defined(Q_WS_X11) + // Note that this one does not really exist + return "qt4x11"; +# elif defined(Q_OS_MAC) + return "cocoa"; +# elif defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) + return "windows"; +# else + LYXERR0("Unknown platform!"); + return "unknown"; +# endif +} +#endif + + double GuiApplication::pixelRatio() const { #if QT_VERSION >= 0x050000 @@ -1108,7 +1249,7 @@ void GuiApplication::clearSession() docstring Application::iconName(FuncRequest const & f, bool unknown) { - return qstring_to_ucs4(lyx::frontend::iconName(f, unknown, false).first); + return qstring_to_ucs4(lyx::frontend::iconInfo(f, unknown, false).filepath); } @@ -1283,10 +1424,17 @@ bool GuiApplication::getStatus(FuncRequest const & cmd, FuncStatus & flag) const case LFUN_REPEAT: case LFUN_PREFERENCES_SAVE: case LFUN_BUFFER_SAVE_AS_DEFAULT: - case LFUN_DEBUG_LEVEL_SET: // these are handled in our dispatch() break; + case LFUN_DEBUG_LEVEL_SET: { + string bad = Debug::badValue(to_utf8(cmd.argument())); + enable = bad.empty(); + if (!bad.empty()) + flag.message(bformat(_("Bad debug value `%1$s'."), from_utf8(bad))); + break; + } + case LFUN_WINDOW_CLOSE: enable = !d->views_.empty(); break; @@ -1294,6 +1442,7 @@ bool GuiApplication::getStatus(FuncRequest const & cmd, FuncStatus & flag) const case LFUN_BUFFER_NEW: case LFUN_BUFFER_NEW_TEMPLATE: case LFUN_FILE_OPEN: + case LFUN_LYXFILES_OPEN: case LFUN_HELP_OPEN: case LFUN_SCREEN_FONT_UPDATE: case LFUN_SET_COLOR: @@ -1391,7 +1540,7 @@ DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd) { DispatchResult dr; - Buffer * buffer = 0; + Buffer * buffer = nullptr; if (cmd.view_origin() && current_view_ != cmd.view_origin()) { //setCurrentView(cmd.view_origin); //does not work dr.setError(true); @@ -1406,13 +1555,16 @@ DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd) dr.screenUpdate(Update::FitCursor); { - // This handles undo groups automagically + // All the code is kept inside the undo group because + // updateBuffer can create undo actions (see #11292) UndoGroupHelper ugh(buffer); dispatch(cmd, dr); - // redraw the screen at the end (first of the two drawing steps). - // This is done unless explicitly requested otherwise. - // This code is kept inside the undo group because updateBuffer - // can create undo actions (see #11292) + if (dr.screenUpdate() & Update::ForceAll) { + for (Buffer const * b : theBufferList()) + b->changed(true); + dr.screenUpdate(dr.screenUpdate() & ~Update::ForceAll); + } + updateCurrentView(cmd, dr); } @@ -1428,7 +1580,7 @@ void GuiApplication::updateCurrentView(FuncRequest const & cmd, DispatchResult & BufferView * bv = current_view_->currentBufferView(); if (bv) { - if (dr.needBufferUpdate()) { + if (dr.needBufferUpdate() || bv->buffer().needUpdate()) { bv->cursor().clearBufferUpdate(); bv->buffer().updateBuffer(); } @@ -1481,8 +1633,8 @@ void GuiApplication::gotoBookmark(unsigned int idx, bool openFile, // if the current buffer is not that one, switch to it. BufferView * doc_bv = current_view_ ? - current_view_->documentBufferView() : 0; - Cursor const * old = doc_bv ? &doc_bv->cursor() : 0; + current_view_->documentBufferView() : nullptr; + Cursor const * old = doc_bv ? &doc_bv->cursor() : nullptr; if (!doc_bv || doc_bv->buffer().fileName() != tmp.filename) { if (switchToBuffer) { dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file)); @@ -1525,8 +1677,10 @@ void GuiApplication::gotoBookmark(unsigned int idx, bool openFile, void GuiApplication::reconfigure(string const & option) { // emit message signal. - if (current_view_) + if (current_view_) { current_view_->message(_("Running configure...")); + current_view_->setCursor(Qt::WaitCursor); + } // Run configure in user lyx directory string const lock_file = package().getConfigureLockName(); @@ -1540,6 +1694,9 @@ void GuiApplication::reconfigure(string const & option) LaTeXPackages::getAvailable(); fileUnlock(fd, lock_file.c_str()); + if (current_view_) + current_view_->unsetCursor(); + if (ret) Alert::information(_("System reconfiguration failed"), _("The system reconfiguration has failed.\n" @@ -1559,7 +1716,7 @@ void GuiApplication::validateCurrentView() // currently at least one view exists but no view has the focus. // choose the last view to make it current. // a view without any open document is preferred. - GuiView * candidate = 0; + GuiView * candidate = nullptr; QHash::const_iterator it = d->views_.begin(); QHash::const_iterator end = d->views_.end(); for (; it != end; ++it) { @@ -1612,9 +1769,10 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; case LFUN_WINDOW_CLOSE: + // FIXME: this is done also in GuiView::closeBuffer()! // update bookmark pit of the current buffer before window close - for (size_t i = 0; i < theSession().bookmarks().size(); ++i) - gotoBookmark(i+1, false, false); + for (size_t i = 1; i < theSession().bookmarks().size(); ++i) + gotoBookmark(i, false, false); // clear the last opened list, because // maybe this will end the session theSession().lastOpened().clear(); @@ -1646,7 +1804,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_BUFFER_NEW: validateCurrentView(); if (!current_view_ - || (!lyxrc.open_buffers_in_tabs && current_view_->documentBufferView() != 0)) { + || (!lyxrc.open_buffers_in_tabs && current_view_->documentBufferView() != nullptr)) { createView(QString(), false); // keep hidden current_view_->newDocument(to_utf8(cmd.argument())); current_view_->show(); @@ -1661,7 +1819,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) string const temp = cmd.getArg(1); validateCurrentView(); if (!current_view_ - || (!lyxrc.open_buffers_in_tabs && current_view_->documentBufferView() != 0)) { + || (!lyxrc.open_buffers_in_tabs && current_view_->documentBufferView() != nullptr)) { createView(); current_view_->newDocument(file, temp, true); if (!current_view_->documentBufferView()) @@ -1677,18 +1835,16 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) // current_view_ is not null. validateCurrentView(); // FIXME: create a new method shared with LFUN_HELP_OPEN. - string const fname = to_utf8(cmd.argument()); + string const fname = trim(to_utf8(cmd.argument()), "\""); bool const is_open = FileName::isAbsolute(fname) && theBufferList().getBuffer(FileName(fname)); if (!current_view_ || (!lyxrc.open_buffers_in_tabs - && current_view_->documentBufferView() != 0 + && current_view_->documentBufferView() != nullptr && !is_open)) { // We want the ui session to be saved per document and not per // window number. The filename crc is a good enough identifier. - boost::crc_32_type crc; - crc = for_each(fname.begin(), fname.end(), crc); - createView(crc.checksum()); + createView(support::checksum(fname)); current_view_->openDocument(fname); if (!current_view_->documentBufferView()) current_view_->close(); @@ -1710,7 +1866,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_HELP_OPEN: { // FIXME: create a new method shared with LFUN_FILE_OPEN. - if (current_view_ == 0) + if (current_view_ == nullptr) createView(); string const arg = to_utf8(cmd.argument()); if (arg.empty()) { @@ -1734,13 +1890,33 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } + case LFUN_LYXFILES_OPEN: { + // This is the actual reason for this method (#12106). + validateCurrentView(); + if (!current_view_ + || (!lyxrc.open_buffers_in_tabs + && current_view_->documentBufferView() != nullptr)) + createView(); + string arg = to_utf8(cmd.argument()); + if (arg.empty()) + // set default + arg = "templates"; + if (arg != "templates" && arg != "examples") { + current_view_->message(_("Wrong argument. Must be 'examples' or 'templates'.")); + break; + } + lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "lyxfiles " + arg)); + break; + } + case LFUN_SET_COLOR: { string const lyx_name = cmd.getArg(0); - string const x11_name = cmd.getArg(1); + string x11_name = cmd.getArg(1); + string x11_darkname = cmd.getArg(2); if (lyx_name.empty() || x11_name.empty()) { if (current_view_) current_view_->message( - _("Syntax: set-color ")); + _("Syntax: set-color ")); break; } @@ -1753,7 +1929,11 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) graphics::GCache::get().changeDisplay(true); #endif - if (!lcolor.setColor(lyx_name, x11_name)) { + if (x11_darkname.empty() && colorCache().isDarkMode()) { + x11_darkname = x11_name; + x11_name.clear(); + } + if (!lcolor.setColor(lyx_name, x11_name, x11_darkname)) { if (current_view_) current_view_->message( bformat(_("Set-color \"%1$s\" failed " @@ -1878,7 +2058,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) string arg = argument; // FIXME: this LFUN should also work without any view. Buffer * buffer = (current_view_ && current_view_->documentBufferView()) - ? &(current_view_->documentBufferView()->buffer()) : 0; + ? &(current_view_->documentBufferView()->buffer()) : nullptr; // This handles undo groups automagically UndoGroupHelper ugh(buffer); while (!arg.empty()) { @@ -1908,7 +2088,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) // all of the buffers might be locally hidden. That is, there is no // active buffer. if (!view || !view->currentBufferView()) - activeBuffers[view] = 0; + activeBuffers[view] = nullptr; else activeBuffers[view] = &view->currentBufferView()->buffer(); @@ -1933,7 +2113,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) GuiView * const homeView = currentView(); Buffer * b = theBufferList().first(); - Buffer * nextBuf = 0; + Buffer * nextBuf = nullptr; int numProcessed = 0; while (true) { if (b != last) @@ -2036,9 +2216,8 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) DocumentClassConstPtr olddc = defaults.params().documentClassPtr(); int const unknown_tokens = defaults.readHeader(lex); DocumentClassConstPtr newdc = defaults.params().documentClassPtr(); - ErrorList el; InsetText & theinset = static_cast(defaults.inset()); - cap::switchBetweenClasses(olddc, newdc, theinset, el); + cap::switchBetweenClasses(olddc, newdc, theinset); if (unknown_tokens != 0) { lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n" @@ -2065,6 +2244,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_BOOKMARK_CLEAR: theSession().bookmarks().clear(); + dr.screenUpdate(Update::Force); break; case LFUN_DEBUG_LEVEL_SET: @@ -2084,7 +2264,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) // is not terminated when closing the last view. // Create a new one to be able to dispatch the // LFUN_DIALOG_SHOW to this view. - if (current_view_ == 0) + if (current_view_ == nullptr) createView(); } } @@ -2097,6 +2277,11 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } + if (current_view_ && current_view_->isFullScreen()) { + if (current_view_->menuBar()->isVisible() && lyxrc.full_screen_menubar) + current_view_->menuBar()->hide(); + } + if (cmd.origin() == FuncRequest::LYXSERVER) updateCurrentView(cmd, dr); } @@ -2179,7 +2364,8 @@ bool GuiApplication::queryKeySym(KeySymbol const & keysym, // seq has been reset at this point func = seq.addkey(keysym, NoModifier); - LYXERR(Debug::KEY, " Key (queried) [action=" << func.action() << "][" + LYXERR(Debug::KEY, " Key (queried) [action=" + << lyxaction.getActionName(func.action()) << "][" << seq.print(KeySequence::Portable) << ']'); return func.action() != LFUN_UNKNOWN_ACTION; } @@ -2206,7 +2392,8 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state) d->cancel_meta_seq.reset(); FuncRequest func = d->cancel_meta_seq.addkey(keysym, state); - LYXERR(Debug::KEY, "action first set to [" << func.action() << ']'); + LYXERR(Debug::KEY, "action first set to [" + << lyxaction.getActionName(func.action()) << ']'); // When not cancel or meta-fake, do the normal lookup. // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards. @@ -2214,7 +2401,8 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state) if ((func.action() != LFUN_CANCEL) && (func.action() != LFUN_META_PREFIX)) { // remove Caps Lock and Mod2 as a modifiers func = d->keyseq.addkey(keysym, (state | d->meta_fake_bit)); - LYXERR(Debug::KEY, "action now set to [" << func.action() << ']'); + LYXERR(Debug::KEY, "action now set to [" + << lyxaction.getActionName(func.action()) << ']'); } // Don't remove this unless you know what you are doing. @@ -2224,8 +2412,9 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state) if (func.action() == LFUN_NOACTION) func = FuncRequest(LFUN_COMMAND_PREFIX); - LYXERR(Debug::KEY, " Key [action=" << func.action() << "][" - << d->keyseq.print(KeySequence::Portable) << ']'); + LYXERR(Debug::KEY, " Key [action=" + << lyxaction.getActionName(func.action()) << "][" + << d->keyseq.print(KeySequence::Portable) << ']'); // already here we know if it any point in going further // why not return already here if action == -1 and @@ -2242,7 +2431,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state) // If addkey looked up a command and did not find further commands then // seq has been reset at this point func = d->keyseq.addkey(keysym, NoModifier); - LYXERR(Debug::KEY, "Action now " << func.action()); + LYXERR(Debug::KEY, "Action now " << lyxaction.getActionName(func.action())); } if (func.action() == LFUN_UNKNOWN_ACTION) { @@ -2359,7 +2548,7 @@ void GuiApplication::resetGui() return; if (d->global_menubar_) - d->menus_.fillMenuBar(d->global_menubar_, 0, false); + d->menus_.fillMenuBar(d->global_menubar_, nullptr, false); QHash::iterator it; for (it = d->views_.begin(); it != d->views_.end(); ++it) { @@ -2419,6 +2608,7 @@ void GuiApplication::createView(QString const & geometry_arg, bool autoShow, int x, y; int w, h; QChar sx, sy; +#if QT_VERSION < 0x060000 QRegExp re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)){0,1}(?:([+-][0-9]*)){0,1}" ); re.indexIn(geometry_arg); w = re.cap(1).toInt(); @@ -2427,6 +2617,16 @@ void GuiApplication::createView(QString const & geometry_arg, bool autoShow, y = re.cap(4).toInt(); sx = re.cap(3).isEmpty() ? '+' : re.cap(3).at(0); sy = re.cap(4).isEmpty() ? '+' : re.cap(4).at(0); +#else + QRegularExpression re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)){0,1}(?:([+-][0-9]*)){0,1}" ); + QRegularExpressionMatch match = re.match(geometry_arg); + w = match.captured(1).toInt(); + h = match.captured(2).toInt(); + x = match.captured(3).toInt(); + y = match.captured(4).toInt(); + sx = match.captured(3).isEmpty() ? '+' : match.captured(3).at(0); + sy = match.captured(4).isEmpty() ? '+' : match.captured(4).at(0); +#endif // Set initial geometry such that we can get the frame size. view->setGeometry(x, y, w, h); int framewidth = view->geometry().x() - view->x(); @@ -2434,7 +2634,11 @@ void GuiApplication::createView(QString const & geometry_arg, bool autoShow, // Negative displacements must be interpreted as distances // from the right or bottom screen borders. if (sx == '-' || sy == '-') { +#if QT_VERSION < 0x060000 QRect rec = QApplication::desktop()->screenGeometry(); +#else + QRect rec = QGuiApplication::primaryScreen()->geometry(); +#endif if (sx == '-') x += rec.width() - w - framewidth; if (sy == '-') @@ -2546,7 +2750,11 @@ void GuiApplication::setGuiLanguage() // opposite. Therefore, long name should be used without truncation. // c.f. http://doc.trolltech.com/4.1/qtranslator.html#load if (!d->qt_trans_.load(language_name, +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QLibraryInfo::path(QLibraryInfo::TranslationsPath))) { +#else QLibraryInfo::location(QLibraryInfo::TranslationsPath))) { +#endif LYXERR(Debug::LOCALE, "Could not find Qt translations for locale " << language_name); } else { @@ -2580,7 +2788,7 @@ void GuiApplication::execBatchCommands() #if QT_VERSION > 0x040600 setAttribute(Qt::AA_MacDontSwapCtrlAndMeta,lyxrc.mac_dontswap_ctrl_meta); #endif -#if QT_VERSION > 0x050100 +#if QT_VERSION >= 0x050000 && QT_VERSION < 0x060000 setAttribute(Qt::AA_UseHighDpiPixmaps,true); #endif // Create the global default menubar which is shown for the dialogs @@ -2647,11 +2855,9 @@ void GuiApplication::restoreGuiSession() for (auto const & last : lastopened) { FileName const & file_name = last.file_name; if (!current_view_ || (!lyxrc.open_buffers_in_tabs - && current_view_->documentBufferView() != 0)) { - boost::crc_32_type crc; + && current_view_->documentBufferView() != nullptr)) { string const & fname = file_name.absFileName(); - crc = for_each(fname.begin(), fname.end(), crc); - createView(crc.checksum()); + createView(support::checksum(fname)); } current_view_->loadDocument(file_name, false); @@ -2819,6 +3025,11 @@ bool GuiApplication::notify(QObject * receiver, QEvent * event) return false; } +bool GuiApplication::isInDarkMode() +{ + return colorCache().isDarkMode(); +} + bool GuiApplication::getRgbColor(ColorCode col, RGBColor & rgbcol) { @@ -2913,7 +3124,7 @@ void GuiApplication::unregisterView(GuiView * gv) if(d->views_.contains(gv->id()) && d->views_.value(gv->id()) == gv) { d->views_.remove(gv->id()); if (current_view_ == gv) - current_view_ = 0; + current_view_ = nullptr; } } @@ -2970,7 +3181,7 @@ void GuiApplication::hideDialogs(string const & name, Inset * inset) const Buffer const * GuiApplication::updateInset(Inset const * inset) const { - Buffer const * buf = 0; + Buffer const * buf = nullptr; QHash::const_iterator end = d->views_.end(); for (QHash::iterator it = d->views_.begin(); it != end; ++it) { if (Buffer const * ptr = (*it)->updateInset(inset)) @@ -2983,7 +3194,7 @@ Buffer const * GuiApplication::updateInset(Inset const * inset) const bool GuiApplication::searchMenu(FuncRequest const & func, docstring_list & names) const { - BufferView * bv = 0; + BufferView * bv = nullptr; if (current_view_) bv = current_view_->currentBufferView(); return d->menus_.searchMenu(func, names, bv); @@ -3002,7 +3213,7 @@ static QStringList uifiles; static QStringList toolbar_uifiles; -GuiApplication::ReturnValues GuiApplication::readUIFile(FileName ui_path) +GuiApplication::ReturnValues GuiApplication::readUIFile(FileName const & ui_path) { enum { ui_menuset = 1, @@ -3204,6 +3415,36 @@ void GuiApplication::onLastWindowClosed() } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)) +void GuiApplication::onApplicationStateChanged(Qt::ApplicationState state) +{ + std::string name = "unknown"; + switch (state) { + case Qt::ApplicationSuspended: + name = "ApplicationSuspended"; + break; + case Qt::ApplicationHidden: + name = "ApplicationHidden"; + break; + case Qt::ApplicationInactive: + name = "ApplicationInactive"; + break; + case Qt::ApplicationActive: + name = "ApplicationActive"; + /// The Dock icon click produces 2 sequential QEvent::ApplicationStateChangeEvent events. + /// cmd+tab only one QEvent::ApplicationStateChangeEvent event + if (d->views_.empty() && d->last_state_ == state) { + LYXERR(Debug::GUI, "Open new window..."); + createView(); + } + break; + } + LYXERR(Debug::GUI, "onApplicationStateChanged..." << name); + d->last_state_ = state; +} +#endif + + void GuiApplication::startLongOperation() { d->key_checker_.start(); }