]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/lyx_gui.C
* src/frontends/*/lyx_gui.C:
[lyx.git] / src / frontends / qt4 / lyx_gui.C
1 /**
2  * \file qt4/lyx_gui.C
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  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "lyx_gui.h"
15
16 // FIXME: move this stuff out again
17 #include "bufferlist.h"
18 #include "BufferView.h"
19 #include "Color.h"
20 #include "funcrequest.h"
21 #include "LColor.h"
22 #include "lyx_main.h"
23 #include "LyXAction.h"
24 #include "lyxfunc.h"
25 #include "lyxrc.h"
26 #include "lyxserver.h"
27 #include "lyxsocket.h"
28
29 #include "graphics/LoaderQueue.h"
30
31 #include "support/lstrings.h"
32 #include "support/os.h"
33 #include "support/package.h"
34 #include "debug.h"
35
36 // Dear Lord, deliver us from Evil, aka the Qt headers
37 // Qt defines a macro 'signals' that clashes with a boost namespace.
38 // All is well if the namespace is visible first.
39 #include <boost/signal.hpp> // FIXME: Is this needed? (Lgb)
40 #include <boost/bind.hpp>
41 #include <boost/shared_ptr.hpp>
42
43 #include "QtView.h"
44 #include "lcolorcache.h"
45 #include "qfont_loader.h"
46 #include "QLImage.h"
47 #include "qt_helpers.h"
48 #include "socket_callback.h"
49
50 #ifdef Q_WS_MACX
51 #include <Carbon/Carbon.h>
52 #endif
53
54 #include <QApplication>
55 #include <QEventLoop>
56 #include <QTranslator>
57 #include <QTextCodec>
58
59 using lyx::support::ltrim;
60 using lyx::support::package;
61
62 using lyx::frontend::QtView;
63
64 namespace os = lyx::support::os;
65
66 using boost::shared_ptr;
67
68 #ifndef CXX_GLOBAL_CSTD
69 using std::exit;
70 #endif
71
72 using std::map;
73 using std::vector;
74 using std::string;
75
76
77 extern BufferList bufferlist;
78
79 namespace {
80
81 int getDPI()
82 {
83         QWidget w;
84         return int(0.5 * (w.logicalDpiX() + w.logicalDpiY()));
85 }
86
87 map<int, shared_ptr<socket_callback> > socket_callbacks;
88
89 } // namespace anon
90
91 // FIXME: wrong place !
92 LyXServer * lyxserver;
93 LyXServerSocket * lyxsocket;
94
95 // in QLyXKeySym.C
96 extern void initEncodings();
97
98 #ifdef Q_WS_X11
99 extern bool lyxX11EventFilter(XEvent * xev);
100 #endif
101
102 #ifdef Q_WS_MACX
103 extern bool macEventFilter(EventRef event);
104 extern pascal OSErr
105 handleOpenDocuments(const AppleEvent* inEvent, AppleEvent* /*reply*/,
106                     long /*refCon*/);
107 #endif
108
109 class LQApplication : public QApplication
110 {
111 public:
112         LQApplication(int & argc, char ** argv);
113         ~LQApplication();
114 #ifdef Q_WS_X11
115         bool x11EventFilter (XEvent * ev) { return lyxX11EventFilter(ev); }
116 #endif
117 #ifdef Q_WS_MACX
118         bool macEventFilter(EventRef event);
119 #endif
120 };
121
122
123 LQApplication::LQApplication(int & argc, char ** argv)
124         : QApplication(argc, argv)
125 {
126 #ifdef Q_WS_MACX
127         AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
128                               NewAEEventHandlerUPP(handleOpenDocuments),
129                               0, false);
130 #endif
131 }
132
133
134 LQApplication::~LQApplication()
135 {}
136
137
138 #ifdef Q_WS_MACX
139 bool LQApplication::macEventFilter(EventRef event)
140 {
141         if (GetEventClass(event) == kEventClassAppleEvent) {
142                 EventRecord eventrec;
143                 ConvertEventRefToEventRecord(event, &eventrec);
144                 AEProcessAppleEvent(&eventrec);
145
146                 return false;
147         }
148         return false;
149 }
150 #endif
151
152
153 namespace {
154
155 LQApplication * app = 0;
156
157 }
158
159
160 namespace lyx_gui {
161
162 bool use_gui = true;
163
164 void parse_init(int & argc, char * argv[])
165 {       
166         /*
167         FIXME : Abdel 29/05/2006 (younes.a@free.fr)
168         reorganize this code. In particular make sure that this
169         advise from Qt documentation is respected:
170         
171                 Since the QApplication object does so much initialization, it
172                 must be created before any other objects related to the user
173                 interface are created.
174         
175         Right now this is not the case. For example, the call to
176         "FontLoader::initFontPath()" below is doned before the QApplication
177         creation. Moreover, I suspect that a number of global variables
178         contains Qt object that are initialized before the passage through
179         parse_init(). This might also explain the message displayed by Qt
180         that caused the hanging:
181
182         QObject::killTimer: timers cannot be stopped from another thread
183         */
184
185         // Force adding of font path _before_ QApplication is initialized
186         FontLoader::initFontPath();
187
188 #ifdef Q_WS_WIN
189         static QApplication win_app(argc, argv);
190 #else
191         app = new LQApplication(argc, argv);
192 #endif
193
194         // install translation file for Qt built-in dialogs
195         // These are only installed since Qt 3.2.x
196         static QTranslator qt_trans(0);
197         if (qt_trans.load(QString("qt_") + QTextCodec::locale(),
198                           qInstallPathTranslations())) {
199                 qApp->installTranslator(&qt_trans);
200                 // even if the language calls for RtL, don't do that
201                 qApp->setReverseLayout(false);
202                 lyxerr[Debug::GUI]
203                         << "Successfully installed Qt translations for locale "
204                         << QTextCodec::locale() << std::endl;
205         } else
206                 lyxerr[Debug::GUI]
207                         << "Could not find  Qt translations for locale "
208                         << QTextCodec::locale() << std::endl;
209
210 /*#ifdef Q_WS_MACX
211         // These translations are meant to break Qt/Mac menu merging
212         // algorithm on some entries. It lists the menu names that
213         // should not be moved to the LyX menu
214         static QTranslator aqua_trans(0);
215         aqua_trans.insert(QTranslatorMessage("QMenuBar", "Setting", 0,
216                                              "do_not_merge_me"));
217         aqua_trans.insert(QTranslatorMessage("QMenuBar", "Config", 0,
218                                              "do_not_merge_me"));
219         aqua_trans.insert(QTranslatorMessage("QMenuBar", "Options", 0,
220                                              "do_not_merge_me"));
221         aqua_trans.insert(QTranslatorMessage("QMenuBar", "Setup", 0,
222                                              "do_not_merge_me"));
223
224         app.installTranslator(&aqua_trans);
225 #endif
226 */
227         using namespace lyx::graphics;
228
229         Image::newImage = boost::bind(&QLImage::newImage);
230         Image::loadableFormats = boost::bind(&QLImage::loadableFormats);
231
232         // needs to be done before reading lyxrc
233         lyxrc.dpi = getDPI();
234
235         LoaderQueue::setPriority(10,100);
236 }
237
238
239 void parse_lyxrc()
240 {}
241
242
243 void start(string const & batch, vector<string> const & files,
244            unsigned int width, unsigned int height, int posx, int posy)
245 {
246         // this can't be done before because it needs the Languages object
247         initEncodings();
248
249         boost::shared_ptr<QtView> view_ptr(new QtView(width, height));
250         LyX::ref().addLyXView(view_ptr);
251
252         QtView & view = *view_ptr.get();
253
254         if (posx != -1 && posy != -1)
255                 view.move(QPoint(posx, posy));
256
257         view.show();
258         view.init();
259
260         // FIXME: some code below needs moving
261
262         lyxserver = new LyXServer(&view.getLyXFunc(), lyxrc.lyxpipes);
263         lyxsocket = new LyXServerSocket(&view.getLyXFunc(),
264                           os::internal_path(package().temp_dir() + "/lyxsocket"));
265
266         for_each(files.begin(), files.end(),
267                  bind(&BufferView::loadLyXFile, view.view(), _1, true));
268
269         // handle the batch commands the user asked for
270         if (!batch.empty()) {
271                 view.getLyXFunc().dispatch(lyxaction.lookupFunc(batch));
272         }
273
274         qApp->exec();
275
276         // FIXME
277         delete lyxsocket;
278         delete lyxserver;
279         lyxserver = 0;
280         delete app;
281 }
282
283
284 void sync_events()
285 {
286         // This is the ONLY place where processEvents may be called.
287         // During screen update/ redraw, this method is disabled to
288         // prevent keyboard events being handed to the LyX core, where
289         // they could cause re-entrant calls to screen update.
290 #if QT_VERSION >= 0x030100
291         qApp->processEvents(QEventLoop::ExcludeUserInput);
292 #endif
293 }
294
295
296 void exit()
297 {
298         delete lyxsocket;
299         delete lyxserver;
300         lyxserver = 0;
301
302         // we cannot call qApp->exit(0) - that could return us
303         // into a static dialog return in the lyx code (for example,
304         // load autosave file QMessageBox. We have to just get the hell
305         // out.
306
307         ::exit(0);
308 }
309
310
311 FuncStatus getStatus(FuncRequest const & ev)
312 {
313         FuncStatus flag;
314         switch (ev.action) {
315         case LFUN_DIALOG_SHOW:
316                 if (ev.argument == "preamble")
317                         flag.unknown(true);
318                 break;
319         case LFUN_TOOLTIPS_TOGGLE:
320                 flag.unknown(true);
321                 break;
322         default:
323                 break;
324         }
325
326         return flag;
327 }
328
329
330 bool getRGBColor(LColor_color col, lyx::RGBColor & rgbcol)
331 {
332         QColor const & qcol = lcolorcache.get(col);
333         if (!qcol.isValid()) {
334                 rgbcol.r = 0;
335                 rgbcol.g = 0;
336                 rgbcol.b = 0;
337                 return false;
338         }
339         rgbcol.r = qcol.red();
340         rgbcol.g = qcol.green();
341         rgbcol.b = qcol.blue();
342         return true;
343 }
344
345
346 string const hexname(LColor_color col)
347 {
348         return ltrim(fromqstr(lcolorcache.get(col).name()), "#");
349 }
350
351
352 void update_color(LColor_color)
353 {
354         // FIXME: Bleh, can't we just clear them all at once ?
355         lcolorcache.clear();
356 }
357
358
359 void update_fonts()
360 {
361         fontloader.update();
362 }
363
364
365 bool font_available(LyXFont const & font)
366 {
367         return fontloader.available(font);
368 }
369
370
371 void register_socket_callback(int fd, boost::function<void()> func)
372 {
373         socket_callbacks[fd] = shared_ptr<socket_callback>(new socket_callback(fd, func));
374 }
375
376
377 void unregister_socket_callback(int fd)
378 {
379         socket_callbacks.erase(fd);
380 }
381
382
383 string const roman_font_name()
384 {
385         if (!use_gui)
386                 return "serif";
387
388         QFont font;
389         font.setStyleHint(QFont::Serif);
390         font.setFamily("serif");
391
392         return fromqstr(QFontInfo(font).family());
393 }
394
395
396 string const sans_font_name()
397 {
398         if (!use_gui)
399                 return "sans";
400
401         QFont font;
402         font.setStyleHint(QFont::SansSerif);
403         font.setFamily("sans");
404
405         return fromqstr(QFontInfo(font).family());
406 }
407
408
409 string const typewriter_font_name()
410 {
411         if (!use_gui)
412                 return "monospace";
413
414         QFont font;
415         font.setStyleHint(QFont::TypeWriter);
416         font.setFamily("monospace");
417
418         return fromqstr(QFontInfo(font).family());
419 }
420
421 }; // namespace lyx_gui