]> git.lyx.org Git - features.git/blob - src/frontends/qt4/GuiApplication.cpp
thrid attempt at changing the naming pattern of the intermediated 'mocced' files
[features.git] / src / frontends / qt4 / GuiApplication.cpp
1 /**
2  * \file GuiApplication.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author unknown
7  * \author John Levon
8  * \author Abdelrazak Younes
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiApplication.h"
16
17 #include "ColorCache.h"
18 #include "GuiClipboard.h"
19 #include "GuiImage.h"
20 #include "GuiKeySymbol.h"
21 #include "GuiSelection.h"
22 #include "GuiView.h"
23 #include "Menus.h"
24 #include "qt_helpers.h"
25 #include "Toolbars.h"
26
27 #include "frontends/alert.h"
28 #include "frontends/Application.h"
29 #include "frontends/FontLoader.h"
30 #include "frontends/FontMetrics.h"
31
32 #include "Buffer.h"
33 #include "BufferList.h"
34 #include "BufferView.h"
35 #include "Color.h"
36 #include "Font.h"
37 #include "FuncRequest.h"
38 #include "FuncStatus.h"
39 #include "Language.h"
40 #include "Lexer.h"
41 #include "LyX.h"
42 #include "LyXAction.h"
43 #include "LyXFunc.h"
44 #include "LyXRC.h"
45 #include "Session.h"
46 #include "version.h"
47
48 #include "support/lassert.h"
49 #include "support/debug.h"
50 #include "support/ExceptionMessage.h"
51 #include "support/FileName.h"
52 #include "support/foreach.h"
53 #include "support/ForkedCalls.h"
54 #include "support/gettext.h"
55 #include "support/lstrings.h"
56 #include "support/lyxalgo.h" // sorted
57 #include "support/Messages.h"
58 #include "support/os.h"
59 #include "support/Package.h"
60
61 #ifdef Q_WS_MACX
62 #include "support/linkback/LinkBackProxy.h"
63 #endif
64
65 #include <QByteArray>
66 #include <QClipboard>
67 #include <QDateTime>
68 #include <QDir>
69 #include <QEventLoop>
70 #include <QFileOpenEvent>
71 #include <QFileInfo>
72 #include <QHash>
73 #include <QIcon>
74 #include <QImageReader>
75 #include <QLocale>
76 #include <QLibraryInfo>
77 #include <QList>
78 #include <QMacPasteboardMime>
79 #include <QMenuBar>
80 #include <QMimeData>
81 #include <QObject>
82 #include <QPixmap>
83 #include <QPixmapCache>
84 #include <QRegExp>
85 #include <QSessionManager>
86 #include <QSettings>
87 #include <QSocketNotifier>
88 #include <QSortFilterProxyModel>
89 #include <QStandardItemModel>
90 #include <QTextCodec>
91 #include <QTimer>
92 #include <QTranslator>
93 #include <QWidget>
94
95 #ifdef Q_WS_X11
96 #include <X11/Xatom.h>
97 #include <X11/Xlib.h>
98 #undef CursorShape
99 #undef None
100 #endif
101
102 #ifdef Q_WS_WIN
103 #include <QWindowsMime>
104 #ifdef Q_CC_GNU
105 #include <wtypes.h>
106 #endif
107 #include <objidl.h>
108 #endif // Q_WS_WIN
109
110 #include <boost/bind.hpp>
111 #include <boost/crc.hpp>
112
113 #include <exception>
114 #include <vector>
115
116 using namespace std;
117 using namespace lyx::support;
118
119
120 static void initializeResources()
121 {
122         static bool initialized = false;
123         if (!initialized) {
124                 Q_INIT_RESOURCE(Resources); 
125                 initialized = true;
126         }
127 }
128
129
130 namespace lyx {
131
132 frontend::Application * createApplication(int & argc, char * argv[])
133 {
134 #ifndef Q_WS_X11
135         // prune -geometry argument(s) by shifting
136         // the following ones 2 places down.
137         for (int i = 0 ; i < argc ; ++i) {
138                 if (strcmp(argv[i], "-geometry") == 0) {
139                         int const remove = (i+1) < argc ? 2 : 1;
140                         argc -= remove;
141                         for (int j = i; j < argc; ++j)
142                                 argv[j] = argv[j + remove];
143                         --i;
144                 }
145         }
146 #endif
147         return new frontend::GuiApplication(argc, argv);
148 }
149
150 namespace frontend {
151
152
153 /// Return the list of loadable formats.
154 vector<string> loadableImageFormats()
155 {
156         vector<string> fmts;
157
158         QList<QByteArray> qt_formats = QImageReader::supportedImageFormats();
159
160         LYXERR(Debug::GRAPHICS,
161                 "\nThe image loader can load the following directly:\n");
162
163         if (qt_formats.empty())
164                 LYXERR(Debug::GRAPHICS, "\nQt4 Problem: No Format available!");
165
166         for (QList<QByteArray>::const_iterator it = qt_formats.begin(); it != qt_formats.end(); ++it) {
167
168                 LYXERR(Debug::GRAPHICS, (const char *) *it << ", ");
169
170                 string ext = ascii_lowercase((const char *) *it);
171                 // special case
172                 if (ext == "jpeg")
173                         ext = "jpg";
174                 fmts.push_back(ext);
175         }
176
177         return fmts;
178 }
179
180
181 class FuncRequestEvent : public QEvent
182 {
183 public:
184        FuncRequestEvent(FuncRequest const & req) 
185        : QEvent(QEvent::User), request(req) {}
186
187        FuncRequest const request;
188 };
189
190
191 ////////////////////////////////////////////////////////////////////////
192 // Icon loading support code.
193 ////////////////////////////////////////////////////////////////////////
194
195 namespace {
196
197 struct PngMap {
198         QString key;
199         QString value;
200 };
201
202
203 bool operator<(PngMap const & lhs, PngMap const & rhs)
204 {
205         return lhs.key < rhs.key;
206 }
207
208
209 class CompareKey {
210 public:
211         CompareKey(QString const & name) : name_(name) {}
212         bool operator()(PngMap const & other) const { return other.key == name_; }
213 private:
214         QString const name_;
215 };
216
217
218 // this must be sorted alphabetically
219 // Upper case comes before lower case
220 PngMap sorted_png_map[] = {
221         { "Bumpeq", "bumpeq2" },
222         { "Cap", "cap2" },
223         { "Cup", "cup2" },
224         { "Delta", "delta2" },
225         { "Downarrow", "downarrow2" },
226         { "Gamma", "gamma2" },
227         { "Lambda", "lambda2" },
228         { "Leftarrow", "leftarrow2" },
229         { "Leftrightarrow", "leftrightarrow2" },
230         { "Longleftarrow", "longleftarrow2" },
231         { "Longleftrightarrow", "longleftrightarrow2" },
232         { "Longrightarrow", "longrightarrow2" },
233         { "Omega", "omega2" },
234         { "Phi", "phi2" },
235         { "Pi", "pi2" },
236         { "Psi", "psi2" },
237         { "Rightarrow", "rightarrow2" },
238         { "Sigma", "sigma2" },
239         { "Subset", "subset2" },
240         { "Supset", "supset2" },
241         { "Theta", "theta2" },
242         { "Uparrow", "uparrow2" },
243         { "Updownarrow", "updownarrow2" },
244         { "Upsilon", "upsilon2" },
245         { "Vdash", "vdash3" },
246         { "Vert", "vert2" },
247         { "Xi", "xi2" },
248         { "nLeftarrow", "nleftarrow2" },
249         { "nLeftrightarrow", "nleftrightarrow2" },
250         { "nRightarrow", "nrightarrow2" },
251         { "nVDash", "nvdash3" },
252         { "nvDash", "nvdash2" },
253         { "textrm \\AA", "textrm_AA"},
254         { "textrm \\O", "textrm_O"},
255         { "vDash", "vdash2" }
256 };
257
258 size_t const nr_sorted_png_map = sizeof(sorted_png_map) / sizeof(PngMap);
259
260
261 QString findPng(QString const & name)
262 {
263         PngMap const * const begin = sorted_png_map;
264         PngMap const * const end = begin + nr_sorted_png_map;
265         LASSERT(sorted(begin, end), /**/);
266
267         PngMap const * const it = find_if(begin, end, CompareKey(name));
268
269         QString png_name;
270         if (it != end) {
271                 png_name = it->value;
272         } else {
273                 png_name = name;
274                 png_name.replace('_', "underscore");
275                 png_name.replace(' ', '_');
276
277                 // This way we can have "math-delim { }" on the toolbar.
278                 png_name.replace('(', "lparen");
279                 png_name.replace(')', "rparen");
280                 png_name.replace('[', "lbracket");
281                 png_name.replace(']', "rbracket");
282                 png_name.replace('{', "lbrace");
283                 png_name.replace('}', "rbrace");
284                 png_name.replace('|', "bars");
285                 png_name.replace(',', "thinspace");
286                 png_name.replace(':', "mediumspace");
287                 png_name.replace(';', "thickspace");
288                 png_name.replace('!', "negthinspace");
289         }
290
291         LYXERR(Debug::GUI, "findPng(" << name << ")\n"
292                 << "Looking for math PNG called \"" << png_name << '"');
293         return png_name;
294 }
295
296 } // namespace anon
297
298
299 QString iconName(FuncRequest const & f, bool unknown)
300 {
301         initializeResources();
302         QString name1;
303         QString name2;
304         QString path;
305         switch (f.action) {
306         case LFUN_MATH_INSERT:
307                 if (!f.argument().empty()) {
308                         path = "math/";
309                         name1 = findPng(toqstr(f.argument()).mid(1));
310                 }
311                 break;
312         case LFUN_MATH_DELIM:
313         case LFUN_MATH_BIGDELIM:
314                 path = "math/";
315                 name1 = findPng(toqstr(f.argument()));
316                 break;
317         case LFUN_CALL:
318                 path = "commands/";
319                 name1 = toqstr(f.argument());
320                 break;
321         default:
322                 name2 = toqstr(lyxaction.getActionName(f.action));
323                 name1 = name2;
324
325                 if (!f.argument().empty()) {
326                         name1 = name2 + ' ' + toqstr(f.argument());
327                         name1.replace(' ', '_');
328                 }
329         }
330
331         FileName fname = libFileSearch("images/" + path, name1, "png");
332         if (fname.exists())
333                 return toqstr(fname.absFilename());
334
335         fname = libFileSearch("images/" + path, name2, "png");
336         if (fname.exists())
337                 return toqstr(fname.absFilename());
338
339         path = ":/images/" + path;
340         QDir res(path);
341         if (!res.exists()) {
342                 LYXERR0("Directory " << path << " not found in resource!"); 
343                 return QString();
344         }
345         name1 += ".png";
346         if (res.exists(name1))
347                 return path + name1;
348
349         name2 += ".png";
350         if (res.exists(name2))
351                 return path + name2;
352
353         LYXERR(Debug::GUI, "Cannot find icon for command \""
354                            << lyxaction.getActionName(f.action)
355                            << '(' << to_utf8(f.argument()) << ")\"");
356
357         if (unknown)
358                 return QString(":/images/unknown.png");
359
360         return QString();
361 }
362
363
364 QIcon getIcon(FuncRequest const & f, bool unknown)
365 {
366         QString icon = iconName(f, unknown);
367         if (icon.isEmpty())
368                 return QIcon();
369
370         //LYXERR(Debug::GUI, "Found icon: " << icon);
371         QPixmap pm;
372         if (!pm.load(icon)) {
373                 LYXERR0("Cannot load icon " << icon << " please verify resource system!");
374                 return QIcon();
375         }
376
377         return QIcon(pm);
378 }
379
380
381 ////////////////////////////////////////////////////////////////////////
382 // LyX server support code.
383 ////////////////////////////////////////////////////////////////////////
384 class SocketNotifier : public QSocketNotifier
385 {
386 public:
387         /// connect a connection notification from the LyXServerSocket
388         SocketNotifier(QObject * parent, int fd, Application::SocketCallback func)
389                 : QSocketNotifier(fd, QSocketNotifier::Read, parent), func_(func)
390         {}
391
392 public:
393         /// The callback function
394         Application::SocketCallback func_;
395 };
396
397
398 ////////////////////////////////////////////////////////////////////////
399 // Mac specific stuff goes here...
400 ////////////////////////////////////////////////////////////////////////
401
402 class MenuTranslator : public QTranslator
403 {
404 public:
405         MenuTranslator(QObject * parent)
406                 : QTranslator(parent)
407         {}
408
409         QString translate(const char * /*context*/, 
410           const char * sourceText, 
411           const char * /*comment*/ = 0) 
412         {
413                 string const s = sourceText;
414                 if (s == N_("About %1") || s == N_("Preferences") 
415                                 || s == N_("Reconfigure") || s == N_("Quit %1"))
416                         return qt_(s);
417                 else 
418                         return QString();
419         }
420 };
421
422 class GlobalMenuBar : public QMenuBar
423 {
424 public:
425         ///
426         GlobalMenuBar() : QMenuBar(0) {}
427         
428         ///
429         bool event(QEvent * e)
430         {
431                 if (e->type() == QEvent::ShortcutOverride) {
432                         //          && activeWindow() == 0) {
433                         QKeyEvent * ke = static_cast<QKeyEvent*>(e);
434                         KeySymbol sym;
435                         setKeySymbol(&sym, ke);
436                         theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
437                         e->accept();
438                         return true;
439                 }
440                 return false;
441         }
442 };
443
444 #ifdef Q_WS_MACX
445 // QMacPasteboardMimeGraphics can only be compiled on Mac.
446
447 class QMacPasteboardMimeGraphics : public QMacPasteboardMime
448 {
449 public:
450         QMacPasteboardMimeGraphics()
451                 : QMacPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL)
452         {}
453
454         QString convertorName() { return "Graphics"; }
455
456         QString flavorFor(QString const & mime)
457         {
458                 LYXERR(Debug::ACTION, "flavorFor " << mime);
459                 if (mime == pdfMimeType())
460                         return QLatin1String("com.adobe.pdf");
461                 return QString();
462         }
463
464         QString mimeFor(QString flav)
465         {
466                 LYXERR(Debug::ACTION, "mimeFor " << flav);
467                 if (flav == QLatin1String("com.adobe.pdf"))
468                         return pdfMimeType();
469                 return QString();
470         }
471
472         bool canConvert(QString const & mime, QString flav)
473         {
474                 return mimeFor(flav) == mime;
475         }
476
477         QVariant convertToMime(QString const & /*mime*/, QList<QByteArray> data,
478                 QString /*flav*/)
479         {
480                 if(data.count() > 1)
481                         qWarning("QMacPasteboardMimeGraphics: Cannot handle multiple member data");
482                 return data.first();
483         }
484
485         QList<QByteArray> convertFromMime(QString const & /*mime*/,
486                 QVariant data, QString /*flav*/)
487         {
488                 QList<QByteArray> ret;
489                 ret.append(data.toByteArray());
490                 return ret;
491         }
492 };
493 #endif
494
495 ///////////////////////////////////////////////////////////////
496 // You can find more platform specific stuff
497 // at the end of this file...
498 ///////////////////////////////////////////////////////////////
499
500 ////////////////////////////////////////////////////////////////////////
501 // Windows specific stuff goes here...
502
503 #ifdef Q_WS_WIN
504 // QWindowsMimeMetafile can only be compiled on Windows.
505
506 static FORMATETC cfFromMime(QString const & mimetype)
507 {
508         FORMATETC formatetc;
509         if (mimetype == emfMimeType()) {
510                 formatetc.cfFormat = CF_ENHMETAFILE;
511                 formatetc.tymed = TYMED_ENHMF;
512         } else if (mimetype == wmfMimeType()) {
513                 formatetc.cfFormat = CF_METAFILEPICT;
514                 formatetc.tymed = TYMED_MFPICT;
515         }
516         formatetc.ptd = 0;
517         formatetc.dwAspect = DVASPECT_CONTENT;
518         formatetc.lindex = -1;
519         return formatetc;
520 }
521
522
523 class QWindowsMimeMetafile : public QWindowsMime {
524 public:
525         QWindowsMimeMetafile() {}
526
527         bool canConvertFromMime(FORMATETC const & formatetc,
528                 QMimeData const * mimedata) const
529         {
530                 return false;
531         }
532
533         bool canConvertToMime(QString const & mimetype,
534                 IDataObject * pDataObj) const
535         {
536                 if (mimetype != emfMimeType() && mimetype != wmfMimeType())
537                         return false;
538                 FORMATETC formatetc = cfFromMime(mimetype);
539                 return pDataObj->QueryGetData(&formatetc) == S_OK;
540         }
541
542         bool convertFromMime(FORMATETC const & formatetc,
543                 const QMimeData * mimedata, STGMEDIUM * pmedium) const
544         {
545                 return false;
546         }
547
548         QVariant convertToMime(QString const & mimetype, IDataObject * pDataObj,
549                 QVariant::Type preferredType) const
550         {
551                 QByteArray data;
552                 if (!canConvertToMime(mimetype, pDataObj))
553                         return data;
554
555                 FORMATETC formatetc = cfFromMime(mimetype);
556                 STGMEDIUM s;
557                 if (pDataObj->GetData(&formatetc, &s) != S_OK)
558                         return data;
559
560                 int dataSize;
561                 if (s.tymed == TYMED_ENHMF) {
562                         dataSize = GetEnhMetaFileBits(s.hEnhMetaFile, 0, 0);
563                         data.resize(dataSize);
564                         dataSize = GetEnhMetaFileBits(s.hEnhMetaFile, dataSize,
565                                 (LPBYTE)data.data());
566                 } else if (s.tymed == TYMED_MFPICT) {
567                         dataSize = GetMetaFileBitsEx((HMETAFILE)s.hMetaFilePict, 0, 0);
568                         data.resize(dataSize);
569                         dataSize = GetMetaFileBitsEx((HMETAFILE)s.hMetaFilePict, dataSize,
570                                 (LPBYTE)data.data());
571                 }
572                 data.detach();
573                 ReleaseStgMedium(&s);
574
575                 return data;
576         }
577
578
579         QVector<FORMATETC> formatsForMime(QString const & mimeType,
580                 QMimeData const * mimeData) const
581         {
582                 QVector<FORMATETC> formats;
583                 formats += cfFromMime(mimeType);
584                 return formats;
585         }
586
587         QString mimeForFormat(FORMATETC const & formatetc) const
588         {
589                 switch (formatetc.cfFormat) {
590                 case CF_ENHMETAFILE:
591                         return emfMimeType(); 
592                 case CF_METAFILEPICT:
593                         return wmfMimeType();
594                 }
595                 return QString();
596         }
597 };
598
599 #endif // Q_WS_WIN
600
601 ////////////////////////////////////////////////////////////////////////
602 // GuiApplication::Private definition and implementation.
603 ////////////////////////////////////////////////////////////////////////
604
605 struct GuiApplication::Private
606 {
607         Private(): language_model_(0), global_menubar_(0) {}
608
609         ///
610         QSortFilterProxyModel * language_model_;
611         ///
612         GuiClipboard clipboard_;
613         ///
614         GuiSelection selection_;
615         ///
616         FontLoader font_loader_;
617         ///
618         ColorCache color_cache_;
619         ///
620         QTranslator qt_trans_;
621         ///
622         QHash<int, SocketNotifier *> socket_notifiers_;
623         ///
624         Menus menus_;
625         ///
626         /// The global instance
627         Toolbars toolbars_;
628
629         /// this timer is used for any regular events one wants to
630         /// perform. at present it is used to check if forked processes
631         /// are done.
632         QTimer general_timer_;
633
634         /// Multiple views container.
635         /**
636         * Warning: This must not be a smart pointer as the destruction of the
637         * object is handled by Qt when the view is closed
638         * \sa Qt::WA_DeleteOnClose attribute.
639         */
640         QHash<int, GuiView *> views_;
641
642         /// Only used on mac.
643         GlobalMenuBar * global_menubar_;
644
645 #ifdef Q_WS_MACX
646         /// Linkback mime handler for MacOSX.
647         QMacPasteboardMimeGraphics mac_pasteboard_mime_;
648 #endif
649
650 #ifdef Q_WS_WIN
651         /// WMF Mime handler for Windows clipboard.
652         /// \warning: see comment in ~GuiApplication and in bug 4846.
653         QWindowsMimeMetafile wmf_mime_;
654 #endif
655 };
656
657
658 GuiApplication * guiApp;
659
660 GuiApplication::~GuiApplication()
661 {
662 #ifdef Q_WS_MACX
663         closeAllLinkBackLinks();
664 #endif
665         // FIXME: Work around bug 4846 for Windows Vista and Qt4
666         // (see http://bugzilla.lyx.org/show_bug.cgi?id=4846)
667         // If the clipboard is not cleared, LyX crashes on exit when it is
668         // compiled in release mode and if there is something in the clipboard.
669         // This is related to QWindowsMimeMetafile which is apparently not 
670         // properly destroyed.
671         qApp->clipboard()->clear(QClipboard::Clipboard);
672         delete d;
673 }
674
675
676 GuiApplication::GuiApplication(int & argc, char ** argv)
677         : QApplication(argc, argv),     current_view_(0), d(new GuiApplication::Private)
678 {
679         QString app_name = "LyX";
680         QCoreApplication::setOrganizationName(app_name);
681         QCoreApplication::setOrganizationDomain("lyx.org");
682         QCoreApplication::setApplicationName(app_name + "-" + lyx_version);
683
684         // Install translator for GUI elements.
685         installTranslator(&d->qt_trans_);
686
687         // FIXME: quitOnLastWindowClosed is true by default. We should have a
688         // lyxrc setting for this in order to let the application stay resident.
689         // But then we need some kind of dock icon, at least on Windows.
690         /*
691         if (lyxrc.quit_on_last_window_closed)
692                 setQuitOnLastWindowClosed(false);
693         */
694 #ifdef Q_WS_MACX
695         // FIXME: Do we need a lyxrc setting for this on Mac? This behaviour
696         // seems to be the default case for applications like LyX.
697         setQuitOnLastWindowClosed(false);
698
699         // This allows to translate the strings that appear in the LyX menu.
700         /// A translator suitable for the entries in the LyX menu.
701         /// Only needed with Qt/Mac.
702         installTranslator(new MenuTranslator(this));
703 #endif
704         
705 #ifdef Q_WS_X11
706         // doubleClickInterval() is 400 ms on X11 which is just too long.
707         // On Windows and Mac OS X, the operating system's value is used.
708         // On Microsoft Windows, calling this function sets the double
709         // click interval for all applications. So we don't!
710         QApplication::setDoubleClickInterval(300);
711 #endif
712
713         connect(this, SIGNAL(lastWindowClosed()), this, SLOT(onLastWindowClosed()));
714
715         // needs to be done before reading lyxrc
716         QWidget w;
717         lyxrc.dpi = (w.logicalDpiX() + w.logicalDpiY()) / 2;
718
719         guiApp = this;
720
721         // Set the cache to 5120 kilobytes which corresponds to screen size of
722         // 1280 by 1024 pixels with a color depth of 32 bits.
723         QPixmapCache::setCacheLimit(5120);
724
725         // Initialize RC Fonts
726         if (lyxrc.roman_font_name.empty())
727                 lyxrc.roman_font_name = fromqstr(romanFontName());
728
729         if (lyxrc.sans_font_name.empty())
730                 lyxrc.sans_font_name = fromqstr(sansFontName());
731
732         if (lyxrc.typewriter_font_name.empty())
733                 lyxrc.typewriter_font_name = fromqstr(typewriterFontName());
734
735         d->general_timer_.setInterval(500);
736         connect(&d->general_timer_, SIGNAL(timeout()),
737                 this, SLOT(handleRegularEvents()));
738         d->general_timer_.start();
739 }
740
741
742 void GuiApplication::clearSession()
743 {
744         QSettings settings;
745         settings.clear();
746 }
747
748
749 docstring GuiApplication::iconName(FuncRequest const & f, bool unknown)
750 {
751         return qstring_to_ucs4(lyx::frontend::iconName(f, unknown));
752 }
753
754
755
756 bool GuiApplication::getStatus(FuncRequest const & cmd, FuncStatus & flag) const
757 {
758         bool enable = true;
759
760         switch(cmd.action) {
761
762         case LFUN_WINDOW_CLOSE:
763                 enable = d->views_.size() > 0;
764                 break;
765
766         case LFUN_BUFFER_NEW:
767         case LFUN_BUFFER_NEW_TEMPLATE:
768         case LFUN_FILE_OPEN:
769         case LFUN_SCREEN_FONT_UPDATE:
770         case LFUN_SET_COLOR:
771         case LFUN_WINDOW_NEW:
772         case LFUN_LYX_QUIT:
773                 enable = true;
774                 break;
775
776         default:
777                 return false;
778         }
779
780         if (!enable)
781                 flag.setEnabled(false);
782
783         return true;
784 }
785
786         
787 bool GuiApplication::dispatch(FuncRequest const & cmd)
788 {
789         switch (cmd.action) {
790
791         case LFUN_WINDOW_NEW:
792                 createView(toqstr(cmd.argument()));
793                 break;
794
795         case LFUN_WINDOW_CLOSE:
796                 // update bookmark pit of the current buffer before window close
797                 for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
798                         theLyXFunc().gotoBookmark(i+1, false, false);
799                 current_view_->close();
800                 break;
801
802         case LFUN_LYX_QUIT:
803                 // quitting is triggered by the gui code
804                 // (leaving the event loop).
805                 if (current_view_)
806                         current_view_->message(from_utf8(N_("Exiting.")));
807                 if (closeAllViews())
808                         quit();
809                 break;
810
811         case LFUN_SCREEN_FONT_UPDATE: {
812                 // handle the screen font changes.
813                 d->font_loader_.update();
814                 // Backup current_view_
815                 GuiView * view = current_view_;
816                 // Set current_view_ to zero to forbid GuiWorkArea::redraw()
817                 // to skip the refresh.
818                 current_view_ = 0;
819                 BufferList::iterator it = theBufferList().begin();
820                 BufferList::iterator const end = theBufferList().end();
821                 for (; it != end; ++it)
822                         (*it)->changed();
823                 // Restore current_view_
824                 current_view_ = view;
825                 break;
826         }
827
828         case LFUN_BUFFER_NEW:
829                 if (d->views_.empty()
830                     || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) {
831                         createView(QString(), false); // keep hidden
832                         current_view_->newDocument(to_utf8(cmd.argument()), false);
833                         current_view_->show();
834                         setActiveWindow(current_view_);
835                 } else {
836                         current_view_->newDocument(to_utf8(cmd.argument()), false);
837                 }
838                 break;
839
840         case LFUN_BUFFER_NEW_TEMPLATE:
841                 if (d->views_.empty()
842                     || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) {
843                         createView();
844                         current_view_->newDocument(to_utf8(cmd.argument()), true);
845                         if (!current_view_->buffer())
846                                 current_view_->close();
847                 } else {
848                         current_view_->newDocument(to_utf8(cmd.argument()), true);
849                 }
850                 break;
851
852         case LFUN_FILE_OPEN:
853                 if (d->views_.empty()
854                     || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) {
855                         string const fname = to_utf8(cmd.argument());
856                         // We want the ui session to be saved per document and not per
857                         // window number. The filename crc is a good enough identifier.
858                         boost::crc_32_type crc;
859                         crc = for_each(fname.begin(), fname.end(), crc);
860                         createView(crc.checksum());
861                         current_view_->openDocument(fname);
862                         if (current_view_ && !current_view_->buffer())
863                                 current_view_->close();
864                 } else
865                         current_view_->openDocument(to_utf8(cmd.argument()));
866                 break;
867
868         case LFUN_SET_COLOR: {
869                 string lyx_name;
870                 string const x11_name = split(to_utf8(cmd.argument()), lyx_name, ' ');
871                 if (lyx_name.empty() || x11_name.empty()) {
872                         current_view_->message(
873                                 _("Syntax: set-color <lyx_name> <x11_name>"));
874                         break;
875                 }
876
877                 string const graphicsbg = lcolor.getLyXName(Color_graphicsbg);
878                 bool const graphicsbg_changed = lyx_name == graphicsbg
879                         && x11_name != graphicsbg;
880                 if (graphicsbg_changed) {
881                         // FIXME: The graphics cache no longer has a changeDisplay method.
882 #if 0
883                         graphics::GCache::get().changeDisplay(true);
884 #endif
885                 }
886
887                 if (!lcolor.setColor(lyx_name, x11_name)) {
888                         current_view_->message(
889                                         bformat(_("Set-color \"%1$s\" failed "
890                                                                "- color is undefined or "
891                                                                "may not be redefined"),
892                                                                    from_utf8(lyx_name)));
893                         break;
894                 }
895                 // Make sure we don't keep old colors in cache.
896                 d->color_cache_.clear();
897                 break;
898         }
899
900         default:
901                 // Notify the caller that the action has not been dispatched.
902                 return false;
903         }
904
905         // The action has been dispatched.
906         return true;
907 }
908
909
910 void GuiApplication::resetGui()
911 {
912         // Set the language defined by the user.
913         setGuiLanguage();
914
915         // Read menus
916         if (!readUIFile(toqstr(lyxrc.ui_file)))
917                 // Gives some error box here.
918                 return;
919
920         if (d->global_menubar_)
921                 d->menus_.fillMenuBar(d->global_menubar_, 0, false);
922
923         QHash<int, GuiView *>::iterator it;
924         for (it = d->views_.begin(); it != d->views_.end(); ++it) {
925                 GuiView * gv = *it;
926                 gv->setLayoutDirection(layoutDirection());
927                 gv->resetDialogs();
928         }
929
930         dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
931 }
932
933
934 void GuiApplication::createView(int view_id)
935 {
936         createView(QString(), true, view_id);
937 }
938
939
940 void GuiApplication::createView(QString const & geometry_arg, bool autoShow,
941         int view_id)
942 {
943         // release the keyboard which might have been grabed by the global
944         // menubar on Mac to catch shortcuts even without any GuiView.
945         if (d->global_menubar_)
946                 d->global_menubar_->releaseKeyboard();
947
948         // create new view
949         int id = view_id;
950         if (id == 0) {
951                 while (d->views_.find(id) != d->views_.end())
952                         id++;
953         }
954         LYXERR(Debug::GUI, "About to create new window with ID " << id);
955         GuiView * view = new GuiView(id);
956         // register view
957         d->views_[id] = view;
958
959         if (autoShow) {
960                 view->show();
961                 setActiveWindow(view);
962         }
963
964         if (!geometry_arg.isEmpty()) {
965 #ifdef Q_WS_WIN
966                 int x, y;
967                 int w, h;
968                 QRegExp re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)([+-][0-9]*)){0,1}" );
969                 re.indexIn(geometry_arg);
970                 w = re.cap(1).toInt();
971                 h = re.cap(2).toInt();
972                 x = re.cap(3).toInt();
973                 y = re.cap(4).toInt();
974                 view->setGeometry(x, y, w, h);
975 #endif
976         }
977         view->setFocus();
978 }
979
980
981 Clipboard & GuiApplication::clipboard()
982 {
983         return d->clipboard_;
984 }
985
986
987 Selection & GuiApplication::selection()
988 {
989         return d->selection_;
990 }
991
992
993 FontLoader & GuiApplication::fontLoader() 
994 {
995         return d->font_loader_;
996 }
997
998
999 Toolbars const & GuiApplication::toolbars() const 
1000 {
1001         return d->toolbars_;
1002 }
1003
1004
1005 Toolbars & GuiApplication::toolbars()
1006 {
1007         return d->toolbars_; 
1008 }
1009
1010
1011 Menus const & GuiApplication::menus() const 
1012 {
1013         return d->menus_;
1014 }
1015
1016
1017 Menus & GuiApplication::menus()
1018 {
1019         return d->menus_; 
1020 }
1021
1022
1023 QList<int> GuiApplication::viewIds() const
1024 {
1025         return d->views_.keys();
1026 }
1027
1028
1029 ColorCache & GuiApplication::colorCache()
1030 {
1031         return d->color_cache_;
1032 }
1033
1034
1035 int GuiApplication::exec()
1036 {
1037         // asynchronously handle batch commands. This event will be in
1038         // the event queue in front of other asynchronous events. Hence,
1039         // we can assume in the latter that the gui is setup already.
1040         QTimer::singleShot(0, this, SLOT(execBatchCommands()));
1041
1042         return QApplication::exec();
1043 }
1044
1045
1046 void GuiApplication::exit(int status)
1047 {
1048         QApplication::exit(status);
1049 }
1050
1051
1052 void GuiApplication::setGuiLanguage()
1053 {
1054         // Set the language defined by the user.
1055         setRcGuiLanguage();
1056
1057         QString const default_language = toqstr(Messages::defaultLanguage());
1058         LYXERR(Debug::LOCALE, "Tring to set default locale to: " << default_language);
1059         QLocale const default_locale(default_language);
1060         QLocale::setDefault(default_locale);
1061
1062         // install translation file for Qt built-in dialogs
1063         QString const language_name = QString("qt_") + default_locale.name();
1064
1065         // language_name can be short (e.g. qt_zh) or long (e.g. qt_zh_CN). 
1066         // Short-named translator can be loaded from a long name, but not the
1067         // opposite. Therefore, long name should be used without truncation.
1068         // c.f. http://doc.trolltech.com/4.1/qtranslator.html#load
1069         if (!d->qt_trans_.load(language_name,
1070                         QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
1071                 LYXERR(Debug::LOCALE, "Could not find  Qt translations for locale "
1072                         << language_name);
1073         } else {
1074                 LYXERR(Debug::LOCALE, "Successfully installed Qt translations for locale "
1075                         << language_name);
1076         }
1077
1078         switch (default_locale.language()) {
1079         case QLocale::Arabic :
1080         case QLocale::Hebrew :
1081         case QLocale::Persian :
1082         case QLocale::Urdu :
1083         setLayoutDirection(Qt::RightToLeft);
1084                 break;
1085         default:
1086         setLayoutDirection(Qt::LeftToRight);
1087         }
1088 }
1089
1090
1091 void GuiApplication::execBatchCommands()
1092 {
1093         setGuiLanguage();
1094
1095         // Read menus
1096         if (!readUIFile(toqstr(lyxrc.ui_file)))
1097                 // Gives some error box here.
1098                 return;
1099
1100 #ifdef Q_WS_MACX
1101         // Create the global default menubar which is shown for the dialogs
1102         // and if no GuiView is visible.
1103         // This must be done after the session was recovered to know the "last files".
1104         d->global_menubar_ = new GlobalMenuBar();
1105         d->menus_.fillMenuBar(d->global_menubar_, 0, true);
1106 #endif
1107
1108         lyx::execBatchCommands();
1109 }
1110
1111
1112 QAbstractItemModel * GuiApplication::languageModel()
1113 {
1114         if (d->language_model_)
1115                 return d->language_model_;
1116
1117         QStandardItemModel * lang_model = new QStandardItemModel(this);
1118         lang_model->insertColumns(0, 1);
1119         int current_row;
1120         Languages::const_iterator it = languages.begin();
1121         Languages::const_iterator end = languages.end();
1122         for (; it != end; ++it) {
1123                 current_row = lang_model->rowCount();
1124                 lang_model->insertRows(current_row, 1);
1125                 QModelIndex item = lang_model->index(current_row, 0);
1126                 lang_model->setData(item, qt_(it->second.display()), Qt::DisplayRole);
1127                 lang_model->setData(item, toqstr(it->second.lang()), Qt::UserRole);
1128         }
1129         d->language_model_ = new QSortFilterProxyModel(this);
1130         d->language_model_->setSourceModel(lang_model);
1131 #if QT_VERSION >= 0x040300
1132         d->language_model_->setSortLocaleAware(true);
1133 #endif
1134         return d->language_model_;
1135 }
1136
1137
1138 void GuiApplication::restoreGuiSession()
1139 {
1140         if (!lyxrc.load_session)
1141                 return;
1142
1143         Session & session = theSession();
1144         vector<FileName> const & lastopened = session.lastOpened().getfiles();
1145         // do not add to the lastfile list since these files are restored from
1146         // last session, and should be already there (regular files), or should
1147         // not be added at all (help files).
1148         for_each(lastopened.begin(), lastopened.end(),
1149                 bind(&GuiView::loadDocument, current_view_, _1, false));
1150
1151         // clear this list to save a few bytes of RAM
1152         session.lastOpened().clear();
1153 }
1154
1155
1156 QString const GuiApplication::romanFontName()
1157 {
1158         QFont font;
1159         font.setKerning(false);
1160         font.setStyleHint(QFont::Serif);
1161         font.setFamily("serif");
1162
1163         return QFontInfo(font).family();
1164 }
1165
1166
1167 QString const GuiApplication::sansFontName()
1168 {
1169         QFont font;
1170         font.setKerning(false);
1171         font.setStyleHint(QFont::SansSerif);
1172         font.setFamily("sans");
1173
1174         return QFontInfo(font).family();
1175 }
1176
1177
1178 QString const GuiApplication::typewriterFontName()
1179 {
1180         QFont font;
1181         font.setKerning(false);
1182         font.setStyleHint(QFont::TypeWriter);
1183         font.setFamily("monospace");
1184
1185         return QFontInfo(font).family();
1186 }
1187
1188
1189 void GuiApplication::handleRegularEvents()
1190 {
1191         ForkedCallsController::handleCompletedProcesses();
1192 }
1193
1194
1195 void GuiApplication::customEvent(QEvent * event)
1196 {
1197        FuncRequestEvent * reqEv = static_cast<FuncRequestEvent *>(event);
1198        lyx::dispatch(reqEv->request);
1199 }
1200
1201
1202 bool GuiApplication::event(QEvent * e)
1203 {
1204         switch(e->type()) {
1205         case QEvent::FileOpen: {
1206                 // Open a file; this happens only on Mac OS X for now.
1207                 //
1208                 // We do this asynchronously because on startup the batch
1209                 // commands are not executed here yet and the gui is not ready
1210                 // therefore.
1211                 QFileOpenEvent * foe = static_cast<QFileOpenEvent *>(e);
1212                 postEvent(this, new FuncRequestEvent(FuncRequest(LFUN_FILE_OPEN,
1213                         qstring_to_ucs4(foe->file()))));
1214                 e->accept();
1215                 return true;
1216         }
1217         default:
1218                 return QApplication::event(e);
1219         }
1220 }
1221
1222
1223 bool GuiApplication::notify(QObject * receiver, QEvent * event)
1224 {
1225         try {
1226                 return QApplication::notify(receiver, event);
1227         }
1228         catch (ExceptionMessage const & e) {
1229                 switch(e.type_) { 
1230                 case ErrorException:
1231                         emergencyCleanup();
1232                         setQuitOnLastWindowClosed(false);
1233                         closeAllViews();
1234                         Alert::error(e.title_, e.details_);
1235 #ifndef NDEBUG
1236                         // Properly crash in debug mode in order to get a useful backtrace.
1237                         abort();
1238 #endif
1239                         // In release mode, try to exit gracefully.
1240                         this->exit(1);
1241
1242                 case BufferException: {
1243                         Buffer * buf = current_view_->buffer();
1244                         docstring details = e.details_ + '\n';
1245                         details += theBufferList().emergencyWrite(buf);
1246                         theBufferList().release(buf);
1247                         details += "\n" + _("The current document was closed.");
1248                         Alert::error(e.title_, details);
1249                         return false;
1250                 }
1251                 case WarningException:
1252                         Alert::warning(e.title_, e.details_);
1253                         return false;
1254                 }
1255         }
1256         catch (exception const & e) {
1257                 docstring s = _("LyX has caught an exception, it will now "
1258                         "attempt to save all unsaved documents and exit."
1259                         "\n\nException: ");
1260                 s += from_ascii(e.what());
1261                 Alert::error(_("Software exception Detected"), s);
1262                 lyx_exit(1);
1263         }
1264         catch (...) {
1265                 docstring s = _("LyX has caught some really weird exception, it will "
1266                         "now attempt to save all unsaved documents and exit.");
1267                 Alert::error(_("Software exception Detected"), s);
1268                 lyx_exit(1);
1269         }
1270
1271         return false;
1272 }
1273
1274
1275 bool GuiApplication::getRgbColor(ColorCode col, RGBColor & rgbcol)
1276 {
1277         QColor const & qcol = d->color_cache_.get(col);
1278         if (!qcol.isValid()) {
1279                 rgbcol.r = 0;
1280                 rgbcol.g = 0;
1281                 rgbcol.b = 0;
1282                 return false;
1283         }
1284         rgbcol.r = qcol.red();
1285         rgbcol.g = qcol.green();
1286         rgbcol.b = qcol.blue();
1287         return true;
1288 }
1289
1290
1291 string const GuiApplication::hexName(ColorCode col)
1292 {
1293         return ltrim(fromqstr(d->color_cache_.get(col).name()), "#");
1294 }
1295
1296
1297 void GuiApplication::registerSocketCallback(int fd, SocketCallback func)
1298 {
1299         SocketNotifier * sn = new SocketNotifier(this, fd, func);
1300         d->socket_notifiers_[fd] = sn;
1301         connect(sn, SIGNAL(activated(int)), this, SLOT(socketDataReceived(int)));
1302 }
1303
1304
1305 void GuiApplication::socketDataReceived(int fd)
1306 {
1307         d->socket_notifiers_[fd]->func_();
1308 }
1309
1310
1311 void GuiApplication::unregisterSocketCallback(int fd)
1312 {
1313         d->socket_notifiers_.take(fd)->setEnabled(false);
1314 }
1315
1316
1317 void GuiApplication::commitData(QSessionManager & sm)
1318 {
1319         /// The implementation is required to avoid an application exit
1320         /// when session state save is triggered by session manager.
1321         /// The default implementation sends a close event to all
1322         /// visible top level widgets when session managment allows
1323         /// interaction.
1324         /// We are changing that to close all wiew one by one.
1325         /// FIXME: verify if the default implementation is enough now.
1326         if (sm.allowsInteraction() && !closeAllViews())
1327                 sm.cancel();
1328 }
1329
1330
1331 void GuiApplication::unregisterView(GuiView * gv)
1332 {
1333         LASSERT(d->views_[gv->id()] == gv, /**/);
1334         d->views_.remove(gv->id());
1335         if (current_view_ == gv) {
1336                 current_view_ = 0;
1337                 theLyXFunc().setLyXView(0);
1338         }
1339 }
1340
1341
1342 bool GuiApplication::closeAllViews()
1343 {
1344         if (d->views_.empty())
1345                 return true;
1346
1347         QList<GuiView *> views = d->views_.values();
1348         foreach (GuiView * view, views) {
1349                 if (!view->close())
1350                         return false;
1351         }
1352
1353         d->views_.clear();
1354         return true;
1355 }
1356
1357
1358 GuiView & GuiApplication::view(int id) const
1359 {
1360         LASSERT(d->views_.contains(id), /**/);
1361         return *d->views_.value(id);
1362 }
1363
1364
1365 void GuiApplication::hideDialogs(string const & name, Inset * inset) const
1366 {
1367         QList<GuiView *> views = d->views_.values();
1368         foreach (GuiView * view, views)
1369                 view->hideDialog(name, inset);
1370 }
1371
1372
1373 Buffer const * GuiApplication::updateInset(Inset const * inset) const
1374 {
1375         Buffer const * buffer_ = 0;
1376         QHash<int, GuiView *>::iterator end = d->views_.end();
1377         for (QHash<int, GuiView *>::iterator it = d->views_.begin(); it != end; ++it) {
1378                 if (Buffer const * ptr = (*it)->updateInset(inset))
1379                         buffer_ = ptr;
1380         }
1381         return buffer_;
1382 }
1383
1384
1385 bool GuiApplication::searchMenu(FuncRequest const & func,
1386         docstring_list & names) const
1387 {
1388         return d->menus_.searchMenu(func, names);
1389 }
1390
1391
1392 bool GuiApplication::readUIFile(QString const & name, bool include)
1393 {
1394         enum {
1395                 ui_menuset = 1,
1396                 ui_toolbars,
1397                 ui_toolbarset,
1398                 ui_include,
1399                 ui_last
1400         };
1401
1402         LexerKeyword uitags[] = {
1403                 { "include", ui_include },
1404                 { "menuset", ui_menuset },
1405                 { "toolbars", ui_toolbars },
1406                 { "toolbarset", ui_toolbarset }
1407         };
1408
1409         LYXERR(Debug::INIT, "About to read " << name << "...");
1410
1411         FileName ui_path;
1412         if (include) {
1413                 ui_path = libFileSearch("ui", name, "inc");
1414                 if (ui_path.empty())
1415                         ui_path = libFileSearch("ui", changeExtension(name, "inc"));
1416         } else {
1417                 ui_path = libFileSearch("ui", name, "ui");
1418         }
1419
1420         if (ui_path.empty()) {
1421                 LYXERR(Debug::INIT, "Could not find " << name);
1422                 Alert::warning(_("Could not find UI definition file"),
1423                                bformat(_("Error while reading the configuration file\n%1$s.\n"
1424                                    "Please check your installation."), qstring_to_ucs4(name)));
1425                 return false;
1426         }
1427
1428
1429         // Ensure that a file is read only once (prevents include loops)
1430         static QStringList uifiles;
1431         QString const uifile = toqstr(ui_path.absFilename());
1432         if (uifiles.contains(uifile)) {
1433                 if (!include) {
1434                         // We are reading again the top uifile so reset the safeguard:
1435                         uifiles.clear();
1436                         d->menus_.reset();
1437                         d->toolbars_.reset();
1438                 } else {
1439                         LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1440                                 << "Is this an include loop?");
1441                         return false;
1442                 }
1443         }
1444         uifiles.push_back(uifile);
1445
1446         LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1447
1448         Lexer lex(uitags);
1449         lex.setFile(ui_path);
1450         if (!lex.isOK()) {
1451                 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1452                        << endl;
1453         }
1454
1455         if (lyxerr.debugging(Debug::PARSER))
1456                 lex.printTable(lyxerr);
1457
1458         while (lex.isOK()) {
1459                 switch (lex.lex()) {
1460                 case ui_include: {
1461                         lex.next(true);
1462                         QString const file = toqstr(lex.getString());
1463                         if (!readUIFile(file, true))
1464                                 return false;
1465                         break;
1466                 }
1467                 case ui_menuset:
1468                         d->menus_.read(lex);
1469                         break;
1470
1471                 case ui_toolbarset:
1472                         d->toolbars_.readToolbars(lex);
1473                         break;
1474
1475                 case ui_toolbars:
1476                         d->toolbars_.readToolbarSettings(lex);
1477                         break;
1478
1479                 default:
1480                         if (!rtrim(lex.getString()).empty())
1481                                 lex.printError("LyX::ReadUIFile: "
1482                                                "Unknown menu tag: `$$Token'");
1483                         break;
1484                 }
1485         }
1486
1487         if (include)
1488                 return true;
1489
1490         QSettings settings;
1491         settings.beginGroup("ui_files");
1492         bool touched = false;
1493         for (int i = 0; i != uifiles.size(); ++i) {
1494                 QFileInfo fi(uifiles[i]);
1495                 QDateTime const date_value = fi.lastModified();
1496                 QString const name_key = QString::number(i);
1497                 if (!settings.contains(name_key)
1498                  || settings.value(name_key).toString() != uifiles[i]
1499                  || settings.value(name_key + "/date").toDateTime() != date_value) {
1500                         touched = true;
1501                         settings.setValue(name_key, uifiles[i]);
1502                         settings.setValue(name_key + "/date", date_value);
1503                 }
1504         }
1505         settings.endGroup();
1506         if (touched)
1507                 settings.remove("views");
1508
1509         return true;
1510 }
1511
1512
1513 void GuiApplication::onLastWindowClosed()
1514 {
1515         if (d->global_menubar_)
1516                 d->global_menubar_->grabKeyboard();
1517 }
1518
1519
1520 ////////////////////////////////////////////////////////////////////////
1521 //
1522 // X11 specific stuff goes here...
1523
1524 #ifdef Q_WS_X11
1525 bool GuiApplication::x11EventFilter(XEvent * xev)
1526 {
1527         if (!current_view_)
1528                 return false;
1529
1530         switch (xev->type) {
1531         case SelectionRequest: {
1532                 if (xev->xselectionrequest.selection != XA_PRIMARY)
1533                         break;
1534                 LYXERR(Debug::SELECTION, "X requested selection.");
1535                 BufferView * bv = current_view_->view();
1536                 if (bv) {
1537                         docstring const sel = bv->requestSelection();
1538                         if (!sel.empty())
1539                                 d->selection_.put(sel);
1540                 }
1541                 break;
1542         }
1543         case SelectionClear: {
1544                 if (xev->xselectionclear.selection != XA_PRIMARY)
1545                         break;
1546                 LYXERR(Debug::SELECTION, "Lost selection.");
1547                 BufferView * bv = current_view_->view();
1548                 if (bv)
1549                         bv->clearSelection();
1550                 break;
1551         }
1552         }
1553         return false;
1554 }
1555 #endif
1556
1557 } // namespace frontend
1558
1559
1560 void hideDialogs(std::string const & name, Inset * inset)
1561 {
1562         if (theApp())
1563                 theApp()->hideDialogs(name, inset);
1564 }
1565
1566
1567 ////////////////////////////////////////////////////////////////////
1568 //
1569 // Font stuff
1570 //
1571 ////////////////////////////////////////////////////////////////////
1572
1573 frontend::FontLoader & theFontLoader()
1574 {
1575         LASSERT(frontend::guiApp, /**/);
1576         return frontend::guiApp->fontLoader();
1577 }
1578
1579
1580 frontend::FontMetrics const & theFontMetrics(Font const & f)
1581 {
1582         return theFontMetrics(f.fontInfo());
1583 }
1584
1585
1586 frontend::FontMetrics const & theFontMetrics(FontInfo const & f)
1587 {
1588         LASSERT(frontend::guiApp, /**/);
1589         return frontend::guiApp->fontLoader().metrics(f);
1590 }
1591
1592
1593 ////////////////////////////////////////////////////////////////////
1594 //
1595 // Misc stuff
1596 //
1597 ////////////////////////////////////////////////////////////////////
1598
1599 frontend::Clipboard & theClipboard()
1600 {
1601         LASSERT(frontend::guiApp, /**/);
1602         return frontend::guiApp->clipboard();
1603 }
1604
1605
1606 frontend::Selection & theSelection()
1607 {
1608         LASSERT(frontend::guiApp, /**/);
1609         return frontend::guiApp->selection();
1610 }
1611
1612 } // namespace lyx
1613
1614 #include "moc_GuiApplication.cpp"