2 * \file GuiApplication.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * \author Abdelrazak Younes
10 * Full author contact details are available in file CREDITS.
15 #include "GuiApplication.h"
17 #include "ColorCache.h"
19 #include "GuiClipboard.h"
21 #include "GuiKeySymbol.h"
22 #include "GuiSelection.h"
25 #include "qt_helpers.h"
28 #include "frontends/alert.h"
29 #include "frontends/Application.h"
30 #include "frontends/FontLoader.h"
31 #include "frontends/FontMetrics.h"
34 #include "BufferList.h"
35 #include "BufferView.h"
38 #include "FuncRequest.h"
39 #include "FuncStatus.h"
42 #include "LaTeXFeatures.h"
45 #include "LyXAction.h"
52 #include "support/lassert.h"
53 #include "support/debug.h"
54 #include "support/ExceptionMessage.h"
55 #include "support/FileName.h"
56 #include "support/filetools.h"
57 #include "support/foreach.h"
58 #include "support/ForkedCalls.h"
59 #include "support/gettext.h"
60 #include "support/lstrings.h"
61 #include "support/lyxalgo.h" // sorted
62 #include "support/Messages.h"
63 #include "support/os.h"
64 #include "support/Package.h"
65 #include "support/Path.h"
66 #include "support/Systemcall.h"
69 #include "support/linkback/LinkBackProxy.h"
79 #include <QFileOpenEvent>
83 #include <QImageReader>
85 #include <QLibraryInfo>
87 #include <QMacPasteboardMime>
92 #include <QPixmapCache>
94 #include <QSessionManager>
96 #include <QSocketNotifier>
97 #include <QSortFilterProxyModel>
98 #include <QStandardItemModel>
101 #include <QTranslator>
105 #include <X11/Xatom.h>
106 #include <X11/Xlib.h>
112 #include <QWindowsMime>
119 #include <boost/bind.hpp>
120 #include <boost/crc.hpp>
126 using namespace lyx::support;
129 static void initializeResources()
131 static bool initialized = false;
133 Q_INIT_RESOURCE(Resources);
141 frontend::Application * createApplication(int & argc, char * argv[])
144 // prune -geometry argument(s) by shifting
145 // the following ones 2 places down.
146 for (int i = 0 ; i < argc ; ++i) {
147 if (strcmp(argv[i], "-geometry") == 0) {
148 int const remove = (i+1) < argc ? 2 : 1;
150 for (int j = i; j < argc; ++j)
151 argv[j] = argv[j + remove];
156 return new frontend::GuiApplication(argc, argv);
162 /// Return the list of loadable formats.
163 vector<string> loadableImageFormats()
167 QList<QByteArray> qt_formats = QImageReader::supportedImageFormats();
169 LYXERR(Debug::GRAPHICS,
170 "\nThe image loader can load the following directly:\n");
172 if (qt_formats.empty())
173 LYXERR(Debug::GRAPHICS, "\nQt4 Problem: No Format available!");
175 for (QList<QByteArray>::const_iterator it = qt_formats.begin(); it != qt_formats.end(); ++it) {
177 LYXERR(Debug::GRAPHICS, (const char *) *it << ", ");
179 string ext = ascii_lowercase((const char *) *it);
190 ////////////////////////////////////////////////////////////////////////
192 // Icon loading support code
194 ////////////////////////////////////////////////////////////////////////
204 bool operator<(PngMap const & lhs, PngMap const & rhs)
206 return lhs.key < rhs.key;
212 CompareKey(QString const & name) : name_(name) {}
213 bool operator()(PngMap const & other) const { return other.key == name_; }
219 // this must be sorted alphabetically
220 // Upper case comes before lower case
221 PngMap sorted_png_map[] = {
222 { "Bumpeq", "bumpeq2" },
225 { "Delta", "delta2" },
226 { "Downarrow", "downarrow2" },
227 { "Gamma", "gamma2" },
228 { "Lambda", "lambda2" },
229 { "Leftarrow", "leftarrow2" },
230 { "Leftrightarrow", "leftrightarrow2" },
231 { "Longleftarrow", "longleftarrow2" },
232 { "Longleftrightarrow", "longleftrightarrow2" },
233 { "Longrightarrow", "longrightarrow2" },
234 { "Omega", "omega2" },
238 { "Rightarrow", "rightarrow2" },
239 { "Sigma", "sigma2" },
240 { "Subset", "subset2" },
241 { "Supset", "supset2" },
242 { "Theta", "theta2" },
243 { "Uparrow", "uparrow2" },
244 { "Updownarrow", "updownarrow2" },
245 { "Upsilon", "upsilon2" },
246 { "Vdash", "vdash3" },
249 { "nLeftarrow", "nleftarrow2" },
250 { "nLeftrightarrow", "nleftrightarrow2" },
251 { "nRightarrow", "nrightarrow2" },
252 { "nVDash", "nvdash3" },
253 { "nvDash", "nvdash2" },
254 { "textrm \\AA", "textrm_AA"},
255 { "textrm \\O", "textrm_O"},
256 { "vDash", "vdash2" }
259 size_t const nr_sorted_png_map = sizeof(sorted_png_map) / sizeof(PngMap);
262 QString findPng(QString const & name)
264 PngMap const * const begin = sorted_png_map;
265 PngMap const * const end = begin + nr_sorted_png_map;
266 LASSERT(sorted(begin, end), /**/);
268 PngMap const * const it = find_if(begin, end, CompareKey(name));
272 png_name = it->value;
275 png_name.replace('_', "underscore");
276 png_name.replace(' ', '_');
278 // This way we can have "math-delim { }" on the toolbar.
279 png_name.replace('(', "lparen");
280 png_name.replace(')', "rparen");
281 png_name.replace('[', "lbracket");
282 png_name.replace(']', "rbracket");
283 png_name.replace('{', "lbrace");
284 png_name.replace('}', "rbrace");
285 png_name.replace('|', "bars");
286 png_name.replace(',', "thinspace");
287 png_name.replace(':', "mediumspace");
288 png_name.replace(';', "thickspace");
289 png_name.replace('!', "negthinspace");
292 LYXERR(Debug::GUI, "findPng(" << name << ")\n"
293 << "Looking for math PNG called \"" << png_name << '"');
300 QString iconName(FuncRequest const & f, bool unknown)
302 initializeResources();
307 case LFUN_MATH_INSERT:
308 if (!f.argument().empty()) {
310 name1 = findPng(toqstr(f.argument()).mid(1));
313 case LFUN_MATH_DELIM:
314 case LFUN_MATH_BIGDELIM:
316 name1 = findPng(toqstr(f.argument()));
320 name1 = toqstr(f.argument());
322 case LFUN_COMMAND_ALTERNATIVES: {
323 // use the first of the alternative commands
325 docstring dummy = split(f.argument(), firstcom, ';');
326 name1 = toqstr(firstcom);
327 name1.replace(' ', '_');
331 name2 = toqstr(lyxaction.getActionName(f.action));
334 if (!f.argument().empty()) {
335 name1 = name2 + ' ' + toqstr(f.argument());
336 name1.replace(' ', '_');
337 name1.replace('\\', "backslash");
341 FileName fname = libFileSearch("images/" + path, name1, "png");
343 return toqstr(fname.absFilename());
345 fname = libFileSearch("images/" + path, name2, "png");
347 return toqstr(fname.absFilename());
349 path = ":/images/" + path;
352 LYXERR0("Directory " << path << " not found in resource!");
356 if (res.exists(name1))
360 if (res.exists(name2))
363 LYXERR(Debug::GUI, "Cannot find icon with filename "
364 << "\"" << name1 << "\""
366 << "\"" << name2 << "\""
368 << lyxaction.getActionName(f.action)
369 << '(' << to_utf8(f.argument()) << ")\"");
372 fname = libFileSearch(QString("images/"), "unknown", "png");
374 return toqstr(fname.absFilename());
375 return QString(":/images/unknown.png");
381 QPixmap getPixmap(QString const & path, QString const & name, QString const & ext)
384 FileName fname = libFileSearch(path, name, ext);
385 QString path1 = toqstr(fname.absFilename());
386 QString path2 = ":/" + path + name + "." + ext;
388 if (pixmap.load(path1)) {
391 else if (pixmap.load(path2)) {
395 LYXERR0("Cannot load pixmap \""
396 << path << name << '.' << ext
397 << "\", please verify resource system!");
402 QIcon getIcon(FuncRequest const & f, bool unknown)
404 QString icon = iconName(f, unknown);
408 //LYXERR(Debug::GUI, "Found icon: " << icon);
410 if (!pm.load(icon)) {
411 LYXERR0("Cannot load icon " << icon << " please verify resource system!");
419 ////////////////////////////////////////////////////////////////////////
421 // LyX server support code.
423 ////////////////////////////////////////////////////////////////////////
425 class SocketNotifier : public QSocketNotifier
428 /// connect a connection notification from the LyXServerSocket
429 SocketNotifier(QObject * parent, int fd, Application::SocketCallback func)
430 : QSocketNotifier(fd, QSocketNotifier::Read, parent), func_(func)
434 /// The callback function
435 Application::SocketCallback func_;
439 ////////////////////////////////////////////////////////////////////////
441 // Mac specific stuff goes here...
443 ////////////////////////////////////////////////////////////////////////
445 class MenuTranslator : public QTranslator
448 MenuTranslator(QObject * parent)
449 : QTranslator(parent)
452 QString translate(const char * /*context*/,
453 const char * sourceText,
454 const char * /*comment*/ = 0)
456 string const s = sourceText;
457 if (s == N_("About %1") || s == N_("Preferences")
458 || s == N_("Reconfigure") || s == N_("Quit %1"))
465 class GlobalMenuBar : public QMenuBar
469 GlobalMenuBar() : QMenuBar(0) {}
472 bool event(QEvent * e)
474 if (e->type() == QEvent::ShortcutOverride) {
475 // && activeWindow() == 0) {
476 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
478 setKeySymbol(&sym, ke);
479 guiApp->processKeySym(sym, q_key_state(ke->modifiers()));
488 // QMacPasteboardMimeGraphics can only be compiled on Mac.
490 class QMacPasteboardMimeGraphics : public QMacPasteboardMime
493 QMacPasteboardMimeGraphics()
494 : QMacPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL)
497 QString convertorName() { return "Graphics"; }
499 QString flavorFor(QString const & mime)
501 LYXERR(Debug::ACTION, "flavorFor " << mime);
502 if (mime == pdfMimeType())
503 return QLatin1String("com.adobe.pdf");
507 QString mimeFor(QString flav)
509 LYXERR(Debug::ACTION, "mimeFor " << flav);
510 if (flav == QLatin1String("com.adobe.pdf"))
511 return pdfMimeType();
515 bool canConvert(QString const & mime, QString flav)
517 return mimeFor(flav) == mime;
520 QVariant convertToMime(QString const & /*mime*/, QList<QByteArray> data,
524 qWarning("QMacPasteboardMimeGraphics: Cannot handle multiple member data");
528 QList<QByteArray> convertFromMime(QString const & /*mime*/,
529 QVariant data, QString /*flav*/)
531 QList<QByteArray> ret;
532 ret.append(data.toByteArray());
538 ///////////////////////////////////////////////////////////////
540 // You can find more platform specific stuff at the end of this file...
542 ///////////////////////////////////////////////////////////////
544 ////////////////////////////////////////////////////////////////////////
545 // Windows specific stuff goes here...
548 // QWindowsMimeMetafile can only be compiled on Windows.
550 static FORMATETC cfFromMime(QString const & mimetype)
553 if (mimetype == emfMimeType()) {
554 formatetc.cfFormat = CF_ENHMETAFILE;
555 formatetc.tymed = TYMED_ENHMF;
556 } else if (mimetype == wmfMimeType()) {
557 formatetc.cfFormat = CF_METAFILEPICT;
558 formatetc.tymed = TYMED_MFPICT;
561 formatetc.dwAspect = DVASPECT_CONTENT;
562 formatetc.lindex = -1;
567 class QWindowsMimeMetafile : public QWindowsMime {
569 QWindowsMimeMetafile() {}
571 bool canConvertFromMime(FORMATETC const & formatetc,
572 QMimeData const * mimedata) const
577 bool canConvertToMime(QString const & mimetype,
578 IDataObject * pDataObj) const
580 if (mimetype != emfMimeType() && mimetype != wmfMimeType())
582 FORMATETC formatetc = cfFromMime(mimetype);
583 return pDataObj->QueryGetData(&formatetc) == S_OK;
586 bool convertFromMime(FORMATETC const & formatetc,
587 const QMimeData * mimedata, STGMEDIUM * pmedium) const
592 QVariant convertToMime(QString const & mimetype, IDataObject * pDataObj,
593 QVariant::Type preferredType) const
596 if (!canConvertToMime(mimetype, pDataObj))
599 FORMATETC formatetc = cfFromMime(mimetype);
601 if (pDataObj->GetData(&formatetc, &s) != S_OK)
605 if (s.tymed == TYMED_ENHMF) {
606 dataSize = GetEnhMetaFileBits(s.hEnhMetaFile, 0, 0);
607 data.resize(dataSize);
608 dataSize = GetEnhMetaFileBits(s.hEnhMetaFile, dataSize,
609 (LPBYTE)data.data());
610 } else if (s.tymed == TYMED_MFPICT) {
611 dataSize = GetMetaFileBitsEx((HMETAFILE)s.hMetaFilePict, 0, 0);
612 data.resize(dataSize);
613 dataSize = GetMetaFileBitsEx((HMETAFILE)s.hMetaFilePict, dataSize,
614 (LPBYTE)data.data());
617 ReleaseStgMedium(&s);
623 QVector<FORMATETC> formatsForMime(QString const & mimetype,
624 QMimeData const * mimedata) const
626 QVector<FORMATETC> formats;
627 if (mimetype == emfMimeType() || mimetype == wmfMimeType())
628 formats += cfFromMime(mimetype);
632 QString mimeForFormat(FORMATETC const & formatetc) const
634 switch (formatetc.cfFormat) {
636 return emfMimeType();
637 case CF_METAFILEPICT:
638 return wmfMimeType();
646 ////////////////////////////////////////////////////////////////////////
647 // GuiApplication::Private definition and implementation.
648 ////////////////////////////////////////////////////////////////////////
650 struct GuiApplication::Private
652 Private(): language_model_(0), global_menubar_(0),
653 encoded_last_key(0), meta_fake_bit(NoModifier)
656 /// WMF Mime handler for Windows clipboard.
657 wmf_mime_ = new QWindowsMimeMetafile();
659 initKeySequences(&theTopLevelKeymap());
662 void initKeySequences(KeyMap * kb)
664 keyseq = KeySequence(kb, kb);
665 cancel_meta_seq = KeySequence(kb, kb);
669 QSortFilterProxyModel * language_model_;
671 GuiClipboard clipboard_;
673 GuiSelection selection_;
675 FontLoader font_loader_;
677 ColorCache color_cache_;
679 QTranslator qt_trans_;
681 QHash<int, SocketNotifier *> socket_notifiers_;
685 /// The global instance
688 /// this timer is used for any regular events one wants to
689 /// perform. at present it is used to check if forked processes
691 QTimer general_timer_;
693 /// delayed FuncRequests
694 std::queue<FuncRequest> func_request_queue_;
696 /// the last character added to the key sequence, in UCS4 encoded form
697 char_type encoded_last_key;
702 KeySequence cancel_meta_seq;
704 KeyModifier meta_fake_bit;
706 /// Multiple views container.
708 * Warning: This must not be a smart pointer as the destruction of the
709 * object is handled by Qt when the view is closed
710 * \sa Qt::WA_DeleteOnClose attribute.
712 QHash<int, GuiView *> views_;
714 /// Only used on mac.
715 GlobalMenuBar * global_menubar_;
718 /// Linkback mime handler for MacOSX.
719 QMacPasteboardMimeGraphics mac_pasteboard_mime_;
723 /// WMF Mime handler for Windows clipboard.
724 QWindowsMimeMetafile * wmf_mime_;
729 GuiApplication * guiApp;
731 GuiApplication::~GuiApplication()
734 closeAllLinkBackLinks();
740 GuiApplication::GuiApplication(int & argc, char ** argv)
741 : QApplication(argc, argv), current_view_(0),
742 d(new GuiApplication::Private)
744 QString app_name = "LyX";
745 QCoreApplication::setOrganizationName(app_name);
746 QCoreApplication::setOrganizationDomain("lyx.org");
747 QCoreApplication::setApplicationName(lyx_package);
749 // Install translator for GUI elements.
750 installTranslator(&d->qt_trans_);
752 // FIXME: quitOnLastWindowClosed is true by default. We should have a
753 // lyxrc setting for this in order to let the application stay resident.
754 // But then we need some kind of dock icon, at least on Windows.
756 if (lyxrc.quit_on_last_window_closed)
757 setQuitOnLastWindowClosed(false);
760 // FIXME: Do we need a lyxrc setting for this on Mac? This behaviour
761 // seems to be the default case for applications like LyX.
762 setQuitOnLastWindowClosed(false);
764 // This allows to translate the strings that appear in the LyX menu.
765 /// A translator suitable for the entries in the LyX menu.
766 /// Only needed with Qt/Mac.
767 installTranslator(new MenuTranslator(this));
771 // doubleClickInterval() is 400 ms on X11 which is just too long.
772 // On Windows and Mac OS X, the operating system's value is used.
773 // On Microsoft Windows, calling this function sets the double
774 // click interval for all applications. So we don't!
775 QApplication::setDoubleClickInterval(300);
778 connect(this, SIGNAL(lastWindowClosed()), this, SLOT(onLastWindowClosed()));
780 // needs to be done before reading lyxrc
782 lyxrc.dpi = (w.logicalDpiX() + w.logicalDpiY()) / 2;
786 // Set the cache to 5120 kilobytes which corresponds to screen size of
787 // 1280 by 1024 pixels with a color depth of 32 bits.
788 QPixmapCache::setCacheLimit(5120);
790 // Initialize RC Fonts
791 if (lyxrc.roman_font_name.empty())
792 lyxrc.roman_font_name = fromqstr(romanFontName());
794 if (lyxrc.sans_font_name.empty())
795 lyxrc.sans_font_name = fromqstr(sansFontName());
797 if (lyxrc.typewriter_font_name.empty())
798 lyxrc.typewriter_font_name = fromqstr(typewriterFontName());
800 d->general_timer_.setInterval(500);
801 connect(&d->general_timer_, SIGNAL(timeout()),
802 this, SLOT(handleRegularEvents()));
803 d->general_timer_.start();
807 GuiApplication * theGuiApp()
809 return dynamic_cast<GuiApplication *>(theApp());
813 void GuiApplication::clearSession()
820 docstring GuiApplication::iconName(FuncRequest const & f, bool unknown)
822 return qstring_to_ucs4(lyx::frontend::iconName(f, unknown));
826 LyXView * GuiApplication::currentWindow()
829 /* In LyX/Mac, when a dialog is open, the menus of the
830 application can still be accessed without giving focus to
831 the main window. In this case, we want to disable the menu
832 entries that are buffer or view-related.
834 if (current_view_ && activeWindow() != current_view_)
837 return current_view_;
841 bool GuiApplication::getStatus(FuncRequest const & cmd, FuncStatus & flag) const
847 case LFUN_WINDOW_CLOSE:
848 enable = d->views_.size() > 0;
851 case LFUN_BUFFER_NEW:
852 case LFUN_BUFFER_NEW_TEMPLATE:
855 case LFUN_SCREEN_FONT_UPDATE:
857 case LFUN_WINDOW_NEW:
859 case LFUN_LYXRC_APPLY:
860 case LFUN_COMMAND_PREFIX:
862 case LFUN_META_PREFIX:
863 case LFUN_RECONFIGURE:
864 case LFUN_SERVER_GET_FILENAME:
865 case LFUN_SERVER_NOTIFY:
874 flag.setEnabled(false);
880 // This function runs "configure" and then rereads lyx.defaults to
881 // reconfigure the automatic settings.
882 static void reconfigure(LyXView * lv, string const & option)
884 // emit message signal.
886 lv->message(_("Running configure..."));
888 // Run configure in user lyx directory
889 PathChanger p(package().user_support());
890 string configure_command = package().configure_command();
891 configure_command += option;
893 int ret = one.startscript(Systemcall::Wait, configure_command);
895 // emit message signal.
897 lv->message(_("Reloading configuration..."));
898 lyxrc.read(libFileSearch(QString(), "lyxrc.defaults"));
899 // Re-read packages.lst
900 LaTeXFeatures::getAvailable();
903 Alert::information(_("System reconfiguration failed"),
904 _("The system reconfiguration has failed.\n"
905 "Default textclass is used but LyX may "
906 "not be able to work properly.\n"
907 "Please reconfigure again if needed."));
910 Alert::information(_("System reconfigured"),
911 _("The system has been reconfigured.\n"
912 "You need to restart LyX to make use of any\n"
913 "updated document class specifications."));
917 void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr)
919 switch (cmd.action) {
921 case LFUN_WINDOW_NEW:
922 createView(toqstr(cmd.argument()));
925 case LFUN_WINDOW_CLOSE:
926 // update bookmark pit of the current buffer before window close
927 for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
928 theLyXFunc().gotoBookmark(i+1, false, false);
929 // clear the last opened list, because
930 // maybe this will end the session
931 theSession().lastOpened().clear();
932 current_view_->close();
936 // quitting is triggered by the gui code
937 // (leaving the event loop).
939 current_view_->message(from_utf8(N_("Exiting.")));
944 case LFUN_SCREEN_FONT_UPDATE: {
945 // handle the screen font changes.
946 d->font_loader_.update();
947 // Backup current_view_
948 GuiView * view = current_view_;
949 // Set current_view_ to zero to forbid GuiWorkArea::redraw()
950 // to skip the refresh.
952 BufferList::iterator it = theBufferList().begin();
953 BufferList::iterator const end = theBufferList().end();
954 for (; it != end; ++it)
956 // Restore current_view_
957 current_view_ = view;
961 case LFUN_BUFFER_NEW:
962 if (d->views_.empty()
963 || (!lyxrc.open_buffers_in_tabs && current_view_->documentBufferView() != 0)) {
964 createView(QString(), false); // keep hidden
965 current_view_->newDocument(to_utf8(cmd.argument()), false);
966 current_view_->show();
967 setActiveWindow(current_view_);
969 current_view_->newDocument(to_utf8(cmd.argument()), false);
973 case LFUN_BUFFER_NEW_TEMPLATE:
974 if (d->views_.empty()
975 || (!lyxrc.open_buffers_in_tabs && current_view_->documentBufferView() != 0)) {
977 current_view_->newDocument(to_utf8(cmd.argument()), true);
978 if (!current_view_->documentBufferView())
979 current_view_->close();
981 current_view_->newDocument(to_utf8(cmd.argument()), true);
986 // FIXME: create a new method shared with LFUN_HELP_OPEN.
987 if (d->views_.empty()
988 || (!lyxrc.open_buffers_in_tabs && current_view_->documentBufferView() != 0)) {
989 string const fname = to_utf8(cmd.argument());
990 // We want the ui session to be saved per document and not per
991 // window number. The filename crc is a good enough identifier.
992 boost::crc_32_type crc;
993 crc = for_each(fname.begin(), fname.end(), crc);
994 createView(crc.checksum());
995 current_view_->openDocument(fname);
996 if (current_view_ && !current_view_->documentBufferView())
997 current_view_->close();
999 current_view_->openDocument(to_utf8(cmd.argument()));
1002 case LFUN_HELP_OPEN: {
1003 // FIXME: create a new method shared with LFUN_FILE_OPEN.
1004 if (current_view_ == 0)
1006 string const arg = to_utf8(cmd.argument());
1008 current_view_->message(_("Missing argument"));
1011 FileName fname = i18nLibFileSearch("doc", arg, "lyx");
1013 fname = i18nLibFileSearch("examples", arg, "lyx");
1015 if (fname.empty()) {
1016 lyxerr << "LyX: unable to find documentation file `"
1017 << arg << "'. Bad installation?" << endl;
1020 current_view_->message(bformat(_("Opening help file %1$s..."),
1021 makeDisplayPath(fname.absFilename())));
1022 Buffer * buf = current_view_->loadDocument(fname, false);
1024 current_view_->setBuffer(buf);
1025 buf->updateLabels();
1026 buf->errors("Parse");
1031 case LFUN_SET_COLOR: {
1033 string const x11_name = split(to_utf8(cmd.argument()), lyx_name, ' ');
1034 if (lyx_name.empty() || x11_name.empty()) {
1035 current_view_->message(
1036 _("Syntax: set-color <lyx_name> <x11_name>"));
1040 string const graphicsbg = lcolor.getLyXName(Color_graphicsbg);
1041 bool const graphicsbg_changed = lyx_name == graphicsbg
1042 && x11_name != graphicsbg;
1043 if (graphicsbg_changed) {
1044 // FIXME: The graphics cache no longer has a changeDisplay method.
1046 graphics::GCache::get().changeDisplay(true);
1050 if (!lcolor.setColor(lyx_name, x11_name)) {
1051 current_view_->message(
1052 bformat(_("Set-color \"%1$s\" failed "
1053 "- color is undefined or "
1054 "may not be redefined"),
1055 from_utf8(lyx_name)));
1058 // Make sure we don't keep old colors in cache.
1059 d->color_cache_.clear();
1063 case LFUN_LYXRC_APPLY: {
1064 // reset active key sequences, since the bindings
1065 // are updated (bug 6064)
1067 LyXRC const lyxrc_orig = lyxrc;
1069 istringstream ss(to_utf8(cmd.argument()));
1070 bool const success = lyxrc.read(ss) == 0;
1073 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1074 << "Unable to read lyxrc data"
1079 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1086 case LFUN_COMMAND_PREFIX:
1087 lyx::dispatch(FuncRequest(LFUN_MESSAGE, d->keyseq.printOptions(true)));
1092 d->meta_fake_bit = NoModifier;
1093 GuiView * gv = currentView();
1094 if (gv && gv->currentBufferView())
1095 // cancel any selection
1096 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1097 dr.setMessage(from_ascii(N_("Cancel")));
1100 case LFUN_META_PREFIX:
1101 d->meta_fake_bit = AltModifier;
1102 dr.setMessage(d->keyseq.print(KeySequence::ForGui));
1105 // --- Menus -----------------------------------------------
1106 case LFUN_RECONFIGURE:
1107 // argument is any additional parameter to the configure.py command
1108 reconfigure(currentView(), to_utf8(cmd.argument()));
1111 // --- lyxserver commands ----------------------------
1112 case LFUN_SERVER_GET_FILENAME: {
1113 GuiView * lv = currentView();
1114 LASSERT(lv && lv->documentBufferView(), return);
1115 docstring const fname = from_utf8(
1116 lv->documentBufferView()->buffer().absFileName());
1117 dr.setMessage(fname);
1118 LYXERR(Debug::INFO, "FNAME[" << fname << ']');
1121 case LFUN_SERVER_NOTIFY: {
1122 docstring const dispatch_buffer = d->keyseq.print(KeySequence::Portable);
1123 dr.setMessage(dispatch_buffer);
1124 theServer().notifyClient(to_utf8(dispatch_buffer));
1128 // Notify the caller that the action has not been dispatched.
1129 dr.dispatched(false);
1133 // The action has been dispatched.
1134 dr.dispatched(true);
1138 docstring GuiApplication::viewStatusMessage()
1140 // When meta-fake key is pressed, show the key sequence so far + "M-".
1141 if (d->meta_fake_bit != NoModifier)
1142 return d->keyseq.print(KeySequence::ForGui) + "M-";
1144 // Else, when a non-complete key sequence is pressed,
1145 // show the available options.
1146 if (d->keyseq.length() > 0 && !d->keyseq.deleted())
1147 return d->keyseq.printOptions(true);
1153 void GuiApplication::handleKeyFunc(FuncCode action)
1155 char_type c = d->encoded_last_key;
1157 if (d->keyseq.length())
1159 GuiView * gv = currentView();
1160 LASSERT(gv && gv->currentBufferView(), return);
1161 BufferView * bv = gv->currentBufferView();
1162 bv->getIntl().getTransManager().deadkey(
1163 c, get_accent(action).accent, bv->cursor().innerText(),
1165 // Need to clear, in case the minibuffer calls these
1168 // copied verbatim from do_accent_char
1169 bv->cursor().resetAnchor();
1170 bv->processUpdateFlags(Update::FitCursor);
1174 void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state)
1176 LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
1178 LyXView * lv = theApp()->currentWindow();
1180 // Do nothing if we have nothing (JMarc)
1181 if (!keysym.isOK()) {
1182 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
1183 lv->restartCursor();
1187 if (keysym.isModifier()) {
1188 LYXERR(Debug::KEY, "isModifier true");
1190 lv->restartCursor();
1194 //Encoding const * encoding = lv->documentBufferView()->cursor().getEncoding();
1195 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
1196 // FIXME: encoded_last_key shadows the member variable of the same
1197 // name. Is that intended?
1198 char_type encoded_last_key = keysym.getUCSEncoded();
1200 // Do a one-deep top-level lookup for
1201 // cancel and meta-fake keys. RVDK_PATCH_5
1202 d->cancel_meta_seq.reset();
1204 FuncRequest func = d->cancel_meta_seq.addkey(keysym, state);
1205 LYXERR(Debug::KEY, "action first set to [" << func.action << ']');
1207 // When not cancel or meta-fake, do the normal lookup.
1208 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
1209 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
1210 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
1211 // remove Caps Lock and Mod2 as a modifiers
1212 func = d->keyseq.addkey(keysym, (state | d->meta_fake_bit));
1213 LYXERR(Debug::KEY, "action now set to [" << func.action << ']');
1216 // Dont remove this unless you know what you are doing.
1217 d->meta_fake_bit = NoModifier;
1219 // Can this happen now ?
1220 if (func.action == LFUN_NOACTION)
1221 func = FuncRequest(LFUN_COMMAND_PREFIX);
1223 LYXERR(Debug::KEY, " Key [action=" << func.action << "]["
1224 << d->keyseq.print(KeySequence::Portable) << ']');
1226 // already here we know if it any point in going further
1227 // why not return already here if action == -1 and
1228 // num_bytes == 0? (Lgb)
1230 if (d->keyseq.length() > 1)
1231 lv->message(d->keyseq.print(KeySequence::ForGui));
1234 // Maybe user can only reach the key via holding down shift.
1235 // Let's see. But only if shift is the only modifier
1236 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
1237 LYXERR(Debug::KEY, "Trying without shift");
1238 func = d->keyseq.addkey(keysym, NoModifier);
1239 LYXERR(Debug::KEY, "Action now " << func.action);
1242 if (func.action == LFUN_UNKNOWN_ACTION) {
1243 // Hmm, we didn't match any of the keysequences. See
1244 // if it's normal insertable text not already covered
1246 if (keysym.isText() && d->keyseq.length() == 1) {
1247 LYXERR(Debug::KEY, "isText() is true, inserting.");
1248 func = FuncRequest(LFUN_SELF_INSERT,
1249 FuncRequest::KEYBOARD);
1251 LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
1252 lv->message(_("Unknown function."));
1253 lv->restartCursor();
1258 if (func.action == LFUN_SELF_INSERT) {
1259 if (encoded_last_key != 0) {
1260 docstring const arg(1, encoded_last_key);
1261 lyx::dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
1262 FuncRequest::KEYBOARD));
1263 LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
1266 lyx::dispatch(func);
1273 void GuiApplication::dispatchDelayed(FuncRequest const & func)
1275 d->func_request_queue_.push(func);
1276 QTimer::singleShot(0, this, SLOT(processFuncRequestQueue()));
1280 void GuiApplication::resetGui()
1282 // Set the language defined by the user.
1286 if (!readUIFile(toqstr(lyxrc.ui_file)))
1287 // Gives some error box here.
1290 if (d->global_menubar_)
1291 d->menus_.fillMenuBar(d->global_menubar_, 0, false);
1293 QHash<int, GuiView *>::iterator it;
1294 for (it = d->views_.begin(); it != d->views_.end(); ++it) {
1297 gv->setLayoutDirection(layoutDirection());
1301 lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
1305 void GuiApplication::createView(int view_id)
1307 createView(QString(), true, view_id);
1311 void GuiApplication::createView(QString const & geometry_arg, bool autoShow,
1314 // release the keyboard which might have been grabed by the global
1315 // menubar on Mac to catch shortcuts even without any GuiView.
1316 if (d->global_menubar_)
1317 d->global_menubar_->releaseKeyboard();
1321 while (d->views_.find(id) != d->views_.end())
1324 LYXERR(Debug::GUI, "About to create new window with ID " << id);
1325 GuiView * view = new GuiView(id);
1327 d->views_[id] = view;
1331 setActiveWindow(view);
1334 if (!geometry_arg.isEmpty()) {
1338 QRegExp re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)([+-][0-9]*)){0,1}" );
1339 re.indexIn(geometry_arg);
1340 w = re.cap(1).toInt();
1341 h = re.cap(2).toInt();
1342 x = re.cap(3).toInt();
1343 y = re.cap(4).toInt();
1344 view->setGeometry(x, y, w, h);
1351 Clipboard & GuiApplication::clipboard()
1353 return d->clipboard_;
1357 Selection & GuiApplication::selection()
1359 return d->selection_;
1363 FontLoader & GuiApplication::fontLoader()
1365 return d->font_loader_;
1369 Toolbars const & GuiApplication::toolbars() const
1371 return d->toolbars_;
1375 Toolbars & GuiApplication::toolbars()
1377 return d->toolbars_;
1381 Menus const & GuiApplication::menus() const
1387 Menus & GuiApplication::menus()
1393 QList<int> GuiApplication::viewIds() const
1395 return d->views_.keys();
1399 ColorCache & GuiApplication::colorCache()
1401 return d->color_cache_;
1405 int GuiApplication::exec()
1407 // asynchronously handle batch commands. This event will be in
1408 // the event queue in front of other asynchronous events. Hence,
1409 // we can assume in the latter that the gui is setup already.
1410 QTimer::singleShot(0, this, SLOT(execBatchCommands()));
1412 return QApplication::exec();
1416 void GuiApplication::exit(int status)
1418 QApplication::exit(status);
1422 void GuiApplication::setGuiLanguage()
1424 // Set the language defined by the user.
1427 QString const default_language = toqstr(Messages::defaultLanguage());
1428 LYXERR(Debug::LOCALE, "Tring to set default locale to: " << default_language);
1429 QLocale const default_locale(default_language);
1430 QLocale::setDefault(default_locale);
1432 // install translation file for Qt built-in dialogs
1433 QString const language_name = QString("qt_") + default_locale.name();
1435 // language_name can be short (e.g. qt_zh) or long (e.g. qt_zh_CN).
1436 // Short-named translator can be loaded from a long name, but not the
1437 // opposite. Therefore, long name should be used without truncation.
1438 // c.f. http://doc.trolltech.com/4.1/qtranslator.html#load
1439 if (!d->qt_trans_.load(language_name,
1440 QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
1441 LYXERR(Debug::LOCALE, "Could not find Qt translations for locale "
1444 LYXERR(Debug::LOCALE, "Successfully installed Qt translations for locale "
1448 switch (default_locale.language()) {
1449 case QLocale::Arabic :
1450 case QLocale::Hebrew :
1451 case QLocale::Persian :
1452 case QLocale::Urdu :
1453 setLayoutDirection(Qt::RightToLeft);
1456 setLayoutDirection(Qt::LeftToRight);
1461 void GuiApplication::processFuncRequestQueue()
1463 while (!d->func_request_queue_.empty()) {
1464 lyx::dispatch(d->func_request_queue_.back());
1465 d->func_request_queue_.pop();
1470 void GuiApplication::execBatchCommands()
1475 if (!readUIFile(toqstr(lyxrc.ui_file)))
1476 // Gives some error box here.
1480 // Create the global default menubar which is shown for the dialogs
1481 // and if no GuiView is visible.
1482 // This must be done after the session was recovered to know the "last files".
1483 d->global_menubar_ = new GlobalMenuBar();
1484 d->menus_.fillMenuBar(d->global_menubar_, 0, true);
1487 lyx::execBatchCommands();
1491 QAbstractItemModel * GuiApplication::languageModel()
1493 if (d->language_model_)
1494 return d->language_model_;
1496 QStandardItemModel * lang_model = new QStandardItemModel(this);
1497 lang_model->insertColumns(0, 1);
1499 Languages::const_iterator it = languages.begin();
1500 Languages::const_iterator end = languages.end();
1501 for (; it != end; ++it) {
1502 current_row = lang_model->rowCount();
1503 lang_model->insertRows(current_row, 1);
1504 QModelIndex item = lang_model->index(current_row, 0);
1505 lang_model->setData(item, qt_(it->second.display()), Qt::DisplayRole);
1506 lang_model->setData(item, toqstr(it->second.lang()), Qt::UserRole);
1508 d->language_model_ = new QSortFilterProxyModel(this);
1509 d->language_model_->setSourceModel(lang_model);
1510 #if QT_VERSION >= 0x040300
1511 d->language_model_->setSortLocaleAware(true);
1513 return d->language_model_;
1517 void GuiApplication::restoreGuiSession()
1519 if (!lyxrc.load_session)
1522 Session & session = theSession();
1523 LastOpenedSection::LastOpened const & lastopened =
1524 session.lastOpened().getfiles();
1526 FileName active_file;
1527 // do not add to the lastfile list since these files are restored from
1528 // last session, and should be already there (regular files), or should
1529 // not be added at all (help files).
1530 for (size_t i = 0; i < lastopened.size(); ++i) {
1531 FileName const & file_name = lastopened[i].file_name;
1532 if (d->views_.empty() || (!lyxrc.open_buffers_in_tabs
1533 && current_view_->documentBufferView() != 0)) {
1534 boost::crc_32_type crc;
1535 string const & fname = file_name.absFilename();
1536 crc = for_each(fname.begin(), fname.end(), crc);
1537 createView(crc.checksum());
1539 current_view_->loadDocument(file_name, false);
1541 if (lastopened[i].active)
1542 active_file = file_name;
1545 // Restore last active buffer
1546 Buffer * buffer = theBufferList().getBuffer(active_file);
1548 current_view_->setBuffer(buffer);
1550 // clear this list to save a few bytes of RAM
1551 session.lastOpened().clear();
1555 QString const GuiApplication::romanFontName()
1558 font.setKerning(false);
1559 font.setStyleHint(QFont::Serif);
1560 font.setFamily("serif");
1562 return QFontInfo(font).family();
1566 QString const GuiApplication::sansFontName()
1569 font.setKerning(false);
1570 font.setStyleHint(QFont::SansSerif);
1571 font.setFamily("sans");
1573 return QFontInfo(font).family();
1577 QString const GuiApplication::typewriterFontName()
1580 font.setKerning(false);
1581 font.setStyleHint(QFont::TypeWriter);
1582 font.setFamily("monospace");
1584 return QFontInfo(font).family();
1588 void GuiApplication::handleRegularEvents()
1590 ForkedCallsController::handleCompletedProcesses();
1594 bool GuiApplication::event(QEvent * e)
1597 case QEvent::FileOpen: {
1598 // Open a file; this happens only on Mac OS X for now.
1600 // We do this asynchronously because on startup the batch
1601 // commands are not executed here yet and the gui is not ready
1603 QFileOpenEvent * foe = static_cast<QFileOpenEvent *>(e);
1604 dispatchDelayed(FuncRequest(LFUN_FILE_OPEN, qstring_to_ucs4(foe->file())));
1609 return QApplication::event(e);
1614 bool GuiApplication::notify(QObject * receiver, QEvent * event)
1617 return QApplication::notify(receiver, event);
1619 catch (ExceptionMessage const & e) {
1621 case ErrorException:
1623 setQuitOnLastWindowClosed(false);
1625 Alert::error(e.title_, e.details_);
1627 // Properly crash in debug mode in order to get a useful backtrace.
1630 // In release mode, try to exit gracefully.
1633 case BufferException: {
1634 if (!current_view_->documentBufferView())
1636 Buffer * buf = ¤t_view_->documentBufferView()->buffer();
1637 docstring details = e.details_ + '\n';
1638 details += buf->emergencyWrite();
1639 theBufferList().release(buf);
1640 details += "\n" + _("The current document was closed.");
1641 Alert::error(e.title_, details);
1644 case WarningException:
1645 Alert::warning(e.title_, e.details_);
1649 catch (exception const & e) {
1650 docstring s = _("LyX has caught an exception, it will now "
1651 "attempt to save all unsaved documents and exit."
1653 s += from_ascii(e.what());
1654 Alert::error(_("Software exception Detected"), s);
1658 docstring s = _("LyX has caught some really weird exception, it will "
1659 "now attempt to save all unsaved documents and exit.");
1660 Alert::error(_("Software exception Detected"), s);
1668 bool GuiApplication::getRgbColor(ColorCode col, RGBColor & rgbcol)
1670 QColor const & qcol = d->color_cache_.get(col);
1671 if (!qcol.isValid()) {
1677 rgbcol.r = qcol.red();
1678 rgbcol.g = qcol.green();
1679 rgbcol.b = qcol.blue();
1684 string const GuiApplication::hexName(ColorCode col)
1686 return ltrim(fromqstr(d->color_cache_.get(col).name()), "#");
1690 void GuiApplication::registerSocketCallback(int fd, SocketCallback func)
1692 SocketNotifier * sn = new SocketNotifier(this, fd, func);
1693 d->socket_notifiers_[fd] = sn;
1694 connect(sn, SIGNAL(activated(int)), this, SLOT(socketDataReceived(int)));
1698 void GuiApplication::socketDataReceived(int fd)
1700 d->socket_notifiers_[fd]->func_();
1704 void GuiApplication::unregisterSocketCallback(int fd)
1706 d->socket_notifiers_.take(fd)->setEnabled(false);
1710 void GuiApplication::commitData(QSessionManager & sm)
1712 /// The implementation is required to avoid an application exit
1713 /// when session state save is triggered by session manager.
1714 /// The default implementation sends a close event to all
1715 /// visible top level widgets when session managment allows
1717 /// We are changing that to close all wiew one by one.
1718 /// FIXME: verify if the default implementation is enough now.
1719 if (sm.allowsInteraction() && !closeAllViews())
1724 void GuiApplication::unregisterView(GuiView * gv)
1726 LASSERT(d->views_[gv->id()] == gv, /**/);
1727 d->views_.remove(gv->id());
1728 if (current_view_ == gv)
1733 bool GuiApplication::closeAllViews()
1735 if (d->views_.empty())
1738 // When a view/window was closed before without quitting LyX, there
1739 // are already entries in the lastOpened list.
1740 theSession().lastOpened().clear();
1742 QList<GuiView *> views = d->views_.values();
1743 foreach (GuiView * view, views) {
1753 GuiView & GuiApplication::view(int id) const
1755 LASSERT(d->views_.contains(id), /**/);
1756 return *d->views_.value(id);
1760 void GuiApplication::hideDialogs(string const & name, Inset * inset) const
1762 QList<GuiView *> views = d->views_.values();
1763 foreach (GuiView * view, views)
1764 view->hideDialog(name, inset);
1768 Buffer const * GuiApplication::updateInset(Inset const * inset) const
1770 Buffer const * buffer_ = 0;
1771 QHash<int, GuiView *>::iterator end = d->views_.end();
1772 for (QHash<int, GuiView *>::iterator it = d->views_.begin(); it != end; ++it) {
1773 if (Buffer const * ptr = (*it)->updateInset(inset))
1780 bool GuiApplication::searchMenu(FuncRequest const & func,
1781 docstring_list & names) const
1783 return d->menus_.searchMenu(func, names);
1787 bool GuiApplication::readUIFile(QString const & name, bool include)
1789 LYXERR(Debug::INIT, "About to read " << name << "...");
1793 ui_path = libFileSearch("ui", name, "inc");
1794 if (ui_path.empty())
1795 ui_path = libFileSearch("ui", changeExtension(name, "inc"));
1797 ui_path = libFileSearch("ui", name, "ui");
1800 if (ui_path.empty()) {
1801 static const QString defaultUIFile = "default";
1802 LYXERR(Debug::INIT, "Could not find " << name);
1804 Alert::warning(_("Could not find UI definition file"),
1805 bformat(_("Error while reading the included file\n%1$s\n"
1806 "Please check your installation."), qstring_to_ucs4(name)));
1809 if (name == defaultUIFile) {
1810 LYXERR(Debug::INIT, "Could not find default UI file!!");
1811 Alert::warning(_("Could not find default UI file"),
1812 _("LyX could not find the default UI file!\n"
1813 "Please check your installation."));
1816 Alert::warning(_("Could not find UI definition file"),
1817 bformat(_("Error while reading the configuration file\n%1$s\n"
1818 "Falling back to default.\n"
1819 "Please look under Tools>Preferences>User Interface and\n"
1820 "check which User Interface file you are using."), qstring_to_ucs4(name)));
1821 return readUIFile(defaultUIFile, false);
1824 // Ensure that a file is read only once (prevents include loops)
1825 static QStringList uifiles;
1826 QString const uifile = toqstr(ui_path.absFilename());
1827 if (uifiles.contains(uifile)) {
1829 // We are reading again the top uifile so reset the safeguard:
1832 d->toolbars_.reset();
1834 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1835 << "Is this an include loop?");
1839 uifiles.push_back(uifile);
1841 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1851 LexerKeyword uitags[] = {
1852 { "include", ui_include },
1853 { "menuset", ui_menuset },
1854 { "toolbars", ui_toolbars },
1855 { "toolbarset", ui_toolbarset }
1859 lex.setFile(ui_path);
1861 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1865 if (lyxerr.debugging(Debug::PARSER))
1866 lex.printTable(lyxerr);
1868 // store which ui files define Toolbars
1869 static QStringList toolbar_uifiles;
1871 while (lex.isOK()) {
1872 switch (lex.lex()) {
1875 QString const file = toqstr(lex.getString());
1876 if (!readUIFile(file, true))
1881 d->menus_.read(lex);
1885 d->toolbars_.readToolbars(lex);
1889 d->toolbars_.readToolbarSettings(lex);
1890 toolbar_uifiles.push_back(uifile);
1894 if (!rtrim(lex.getString()).empty())
1895 lex.printError("LyX::ReadUIFile: "
1896 "Unknown menu tag: `$$Token'");
1905 settings.beginGroup("ui_files");
1906 bool touched = false;
1907 for (int i = 0; i != uifiles.size(); ++i) {
1908 QFileInfo fi(uifiles[i]);
1909 QDateTime const date_value = fi.lastModified();
1910 QString const name_key = QString::number(i);
1911 // if an ui file which defines Toolbars has changed,
1912 // we have to reset the settings
1913 if (toolbar_uifiles.contains(uifiles[i])
1914 && (!settings.contains(name_key)
1915 || settings.value(name_key).toString() != uifiles[i]
1916 || settings.value(name_key + "/date").toDateTime() != date_value)) {
1918 settings.setValue(name_key, uifiles[i]);
1919 settings.setValue(name_key + "/date", date_value);
1922 settings.endGroup();
1924 settings.remove("views");
1930 void GuiApplication::onLastWindowClosed()
1932 if (d->global_menubar_)
1933 d->global_menubar_->grabKeyboard();
1937 ////////////////////////////////////////////////////////////////////////
1939 // X11 specific stuff goes here...
1942 bool GuiApplication::x11EventFilter(XEvent * xev)
1947 switch (xev->type) {
1948 case SelectionRequest: {
1949 if (xev->xselectionrequest.selection != XA_PRIMARY)
1951 LYXERR(Debug::SELECTION, "X requested selection.");
1952 BufferView * bv = current_view_->currentBufferView();
1954 docstring const sel = bv->requestSelection();
1956 d->selection_.put(sel);
1960 case SelectionClear: {
1961 if (xev->xselectionclear.selection != XA_PRIMARY)
1963 LYXERR(Debug::SELECTION, "Lost selection.");
1964 BufferView * bv = current_view_->currentBufferView();
1966 bv->clearSelection();
1974 } // namespace frontend
1977 void hideDialogs(std::string const & name, Inset * inset)
1980 theApp()->hideDialogs(name, inset);
1984 ////////////////////////////////////////////////////////////////////
1988 ////////////////////////////////////////////////////////////////////
1990 frontend::FontLoader & theFontLoader()
1992 LASSERT(frontend::guiApp, /**/);
1993 return frontend::guiApp->fontLoader();
1997 frontend::FontMetrics const & theFontMetrics(Font const & f)
1999 return theFontMetrics(f.fontInfo());
2003 frontend::FontMetrics const & theFontMetrics(FontInfo const & f)
2005 LASSERT(frontend::guiApp, /**/);
2006 return frontend::guiApp->fontLoader().metrics(f);
2010 ////////////////////////////////////////////////////////////////////
2014 ////////////////////////////////////////////////////////////////////
2016 frontend::Clipboard & theClipboard()
2018 LASSERT(frontend::guiApp, /**/);
2019 return frontend::guiApp->clipboard();
2023 frontend::Selection & theSelection()
2025 LASSERT(frontend::guiApp, /**/);
2026 return frontend::guiApp->selection();
2032 #include "moc_GuiApplication.cpp"