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