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