]> git.lyx.org Git - features.git/blob - src/frontends/xforms/lyx_gui.C
Wrap most of the frontend code up inside namespace lyx::frontend.
[features.git] / src / frontends / xforms / lyx_gui.C
1 /**
2  * \file xforms/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 Lars Gullik Bjønnes
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 #include "ColorHandler.h"
16 #include "xfont_loader.h"
17 #include "xforms_helpers.h"
18 #include "xformsImage.h"
19 #include "XFormsView.h"
20
21 #include "bufferlist.h"
22 #include "BufferView.h"
23 #include "debug.h"
24 #include "funcrequest.h"
25 #include "gettext.h"
26 #include "LColor.h"
27 #include "lyx_main.h"
28 #include "LyXAction.h"
29 #include "lyxfunc.h"
30 #include "lyxrc.h"
31 #include "lyxserver.h"
32 #include "lyxsocket.h"
33
34 #include "graphics/LoaderQueue.h"
35
36 #include "support/filetools.h"
37 #include "support/lyxlib.h"
38 #include "support/os.h"
39 #include "support/path_defines.h"
40
41 #include "lyx_forms.h"
42
43 #include <boost/bind.hpp>
44
45 #include "support/std_sstream.h"
46 #include <iomanip>
47 #include <fcntl.h>
48
49 using lyx::support::AddName;
50 using lyx::support::user_lyxdir;
51
52 using lyx::frontend::fontloader;
53 using lyx::frontend::getRGBColor;
54 using lyx::frontend::lyxColorHandler;
55 using lyx::frontend::LyXColorHandler;
56 using lyx::frontend::XformsColor;
57 using lyx::frontend::XFormsView;
58
59 namespace os = lyx::support::os;
60
61 #ifndef CXX_GLOBAL_CSTD
62 using std::exit;
63 #endif
64
65 using std::dec;
66 using std::endl;
67 using std::hex;
68 using std::setbase;
69 using std::setfill;
70 using std::setw;
71 using std::ostringstream;
72 using std::vector;
73 using std::string;
74
75
76 extern BufferList bufferlist;
77
78 // FIXME: wrong place !
79 LyXServer * lyxserver;
80 LyXServerSocket * lyxsocket;
81
82 namespace {
83
84 /// quit lyx
85 bool finished = false;
86
87 /// estimate DPI from X server
88 float getDPI()
89 {
90         Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen);
91         return ((HeightOfScreen(scr) * 25.4 / HeightMMOfScreen(scr)) +
92                 (WidthOfScreen(scr) * 25.4 / WidthMMOfScreen(scr))) / 2;
93 }
94
95
96 /// set default GUI configuration
97 void setDefaults()
98 {
99         FL_IOPT cntl;
100         cntl.buttonFontSize = FL_NORMAL_SIZE;
101         cntl.browserFontSize = FL_NORMAL_SIZE;
102         cntl.labelFontSize = FL_NORMAL_SIZE;
103         cntl.choiceFontSize = FL_NORMAL_SIZE;
104         cntl.inputFontSize = FL_NORMAL_SIZE;
105         cntl.menuFontSize  = FL_NORMAL_SIZE;
106         cntl.borderWidth = -1;
107         cntl.vclass = FL_DefaultVisual;
108         fl_set_defaults(FL_PDVisual
109                         | FL_PDButtonFontSize
110                         | FL_PDBrowserFontSize
111                         | FL_PDLabelFontSize
112                         | FL_PDChoiceFontSize
113                         | FL_PDInputFontSize
114                         | FL_PDMenuFontSize
115                         | FL_PDBorderWidth, &cntl);
116 }
117
118
119 extern "C" {
120
121 int LyX_XErrHandler(Display * display, XErrorEvent * xeev) {
122         // We don't abort on BadWindow
123         if (xeev->error_code == BadWindow) {
124                 lyxerr << "BadWindow received !" << endl;
125                 lyxerr << "If you're using xforms 1.0 or greater, "
126                         << " please report this to lyx-devel@lists.lyx.org" << endl;
127                 return 0;
128         }
129
130         // emergency cleanup
131         LyX::cref().emergencyCleanup();
132
133         // Get the reason for the crash.
134         char etxt[513];
135         XGetErrorText(display, xeev->error_code, etxt, 512);
136         lyxerr << etxt << " id: " << xeev->resourceid << endl;
137         // By doing an abort we get a nice backtrace. (hopefully)
138         lyx::support::abort();
139         return 0;
140 }
141
142 }
143
144 /// read in geometry specification
145 char geometry[40];
146
147 } // namespace anon
148
149
150 namespace lyx_gui {
151
152 bool use_gui = true;
153
154
155 void parse_init(int & argc, char * argv[])
156 {
157         setDefaults();
158
159         FL_CMD_OPT cmdopt[] = {
160                 {"-geometry", "*.geometry", XrmoptionSepArg, "690x510"}
161         };
162
163         FL_resource res[] = {
164                 {"geometry", "geometryClass", FL_STRING, geometry, "", 40}
165         };
166
167         const int num_res = sizeof(res)/sizeof(FL_resource);
168
169         fl_initialize(&argc, argv, "LyX", cmdopt, num_res);
170
171         // It appears that, in xforms >=0.89.5, fl_initialize()
172         // calls setlocale() and ruins our LC_NUMERIC setting.
173         locale_init();
174
175         fl_get_app_resources(res, num_res);
176
177         Display * display = fl_get_display();
178
179         if (!display) {
180                 lyxerr << "LyX: unable to access X display, exiting" << endl;
181                 os::warn("Unable to access X display, exiting");
182                 ::exit(1);
183         }
184
185         fcntl(ConnectionNumber(display), F_SETFD, FD_CLOEXEC);
186
187         XSetErrorHandler(LyX_XErrHandler);
188
189         lyxColorHandler.reset(new LyXColorHandler);
190
191         using namespace lyx::graphics;
192
193         // connect the image loader based on the xforms library
194         Image::newImage = boost::bind(&xformsImage::newImage);
195         Image::loadableFormats = boost::bind(&xformsImage::loadableFormats);
196
197         // must do this /before/ lyxrc gets read
198         lyxrc.dpi = getDPI();
199
200         LoaderQueue::setPriority(10,100);
201 }
202
203
204 void parse_lyxrc()
205 {
206         XformsColor::read(AddName(user_lyxdir(), "preferences.xform"));
207
208         if (lyxrc.popup_font_encoding.empty())
209                 lyxrc.popup_font_encoding = lyxrc.font_norm;
210         // Set the font name for popups and menus
211         string boldfontname = lyxrc.popup_bold_font
212                                + "-*-*-*-?-*-*-*-*-"
213                                + lyxrc.popup_font_encoding;
214                 // "?" means "scale that font"
215         string fontname = lyxrc.popup_normal_font
216                                + "-*-*-*-?-*-*-*-*-"
217                                + lyxrc.popup_font_encoding;
218
219         int bold = fl_set_font_name(FL_BOLD_STYLE, boldfontname.c_str());
220         int normal = fl_set_font_name(FL_NORMAL_STYLE, fontname.c_str());
221         if (bold < 0)
222                 lyxerr << "Could not set menu font to "
223                        << boldfontname << endl;
224
225         if (normal < 0)
226                 lyxerr << "Could not set popup font to "
227                        << fontname << endl;
228
229         if (bold < 0 && normal < 0) {
230                 lyxerr << "Using 'helvetica' font for menus" << endl;
231                 boldfontname = "-*-helvetica-bold-r-*-*-*-?-*-*-*-*-iso8859-1";
232                 fontname = "-*-helvetica-medium-r-*-*-*-?-*-*-*-*-iso8859-1";
233                 bold = fl_set_font_name(FL_BOLD_STYLE, boldfontname.c_str());
234                 normal = fl_set_font_name(FL_NORMAL_STYLE, fontname.c_str());
235
236                 if (bold < 0 && normal < 0) {
237                         lyxerr << "Could not find helvetica font. Using 'fixed'." << endl;
238                         fl_set_font_name(FL_NORMAL_STYLE, "fixed");
239                         normal = bold = 0;
240                 }
241         }
242         if (bold < 0)
243                 fl_set_font_name(FL_BOLD_STYLE, fontname.c_str());
244         else if (normal < 0)
245                 fl_set_font_name(FL_NORMAL_STYLE, boldfontname.c_str());
246
247         fl_setpup_fontstyle(FL_NORMAL_STYLE);
248         fl_setpup_fontsize(FL_NORMAL_SIZE);
249         fl_setpup_color(FL_MCOL, FL_BLACK);
250         fl_set_goodies_font(FL_NORMAL_STYLE, FL_NORMAL_SIZE);
251         fl_set_tooltip_font(FL_NORMAL_STYLE, FL_NORMAL_SIZE);
252 }
253
254
255 void start(string const & batch, vector<string> const & files)
256 {
257         // initial geometry
258         int xpos = -1;
259         int ypos = -1;
260         unsigned int width = 690;
261         unsigned int height = 510;
262
263         int const geometryBitmask =
264                 XParseGeometry(geometry,
265                                &xpos, &ypos, &width, &height);
266
267         // if width is not set by geometry, check it against monitor width
268         if (!(geometryBitmask & WidthValue)) {
269                 Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen);
270                 if (WidthOfScreen(scr) - 8 < int(width))
271                         width = WidthOfScreen(scr) - 8;
272         }
273
274         // if height is not set by geometry, check it against monitor height
275         if (!(geometryBitmask & HeightValue)) {
276                 Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen);
277                 if (HeightOfScreen(scr) - 24 < int(height))
278                         height = HeightOfScreen(scr) - 24;
279         }
280
281         Screen * s = ScreenOfDisplay(fl_get_display(), fl_screen);
282
283         // recalculate xpos if it's not set
284         if (xpos == -1)
285                 xpos = (WidthOfScreen(s) - width) / 2;
286
287         // recalculate ypos if it's not set
288         if (ypos == -1)
289                 ypos = (HeightOfScreen(s) - height) / 2;
290
291         lyxerr[Debug::GUI] << "Creating view: " << width << 'x' << height
292                            << '+' << xpos << '+' << ypos << endl;
293
294         boost::shared_ptr<XFormsView> view_ptr(new XFormsView(width, height));
295         LyX::ref().addLyXView(view_ptr);
296
297         XFormsView & view = *view_ptr.get();
298         view.show(xpos, ypos, "LyX");
299         view.init();
300
301         // FIXME: some code below needs moving
302
303         lyxserver = new LyXServer(&view.getLyXFunc(), lyxrc.lyxpipes);
304         lyxsocket = new LyXServerSocket(&view.getLyXFunc(),
305                           os::slashify_path(os::getTmpDir() + "/lyxsocket"));
306
307         vector<string>::const_iterator cit = files.begin();
308         vector<string>::const_iterator end = files.end();
309         for (; cit != end; ++cit)
310                 view.view()->loadLyXFile(*cit, true);
311
312         // handle the batch commands the user asked for
313         if (!batch.empty())
314                 view.getLyXFunc().dispatch(lyxaction.lookupFunc(batch));
315
316         // enter the event loop
317         while (!finished) {
318                 if (fl_check_forms() == FL_EVENT) {
319                         XEvent ev;
320                         fl_XNextEvent(&ev);
321                         lyxerr[Debug::GUI]
322                                 << "Received unhandled X11 event" << endl
323                                 << "Type: " << ev.xany.type
324                                 << " Target: 0x" << hex << ev.xany.window
325                                 << dec << endl;
326                 }
327         }
328
329         // FIXME: breaks emergencyCleanup
330         delete lyxsocket;
331         delete lyxserver;
332 }
333
334
335 void exit()
336 {
337         finished = true;
338 }
339
340
341 void sync_events()
342 {
343         // FIXME
344 }
345
346
347 FuncStatus getStatus(FuncRequest const & /*ev*/)
348 {
349         // Nothing interesting to do here
350         return FuncStatus();
351 }
352
353 string const hexname(LColor_color col)
354 {
355         unsigned int r, g, b;
356         bool const success = getRGBColor(col, r, g, b);
357         if (!success) {
358                 lyxerr << "X can't find color for \"" << lcolor.getLyXName(col)
359                        << '"' << endl;
360                 return string();
361         }
362
363         ostringstream os;
364
365         os << setbase(16) << setfill('0')
366            << setw(2) << r
367            << setw(2) << g
368            << setw(2) << b;
369
370         return os.str();
371 }
372
373
374 void update_color(LColor_color col)
375 {
376         lyxColorHandler->getGCForeground(col);
377         lyxColorHandler->updateColor(col);
378 }
379
380
381 void update_fonts()
382 {
383         fontloader.update();
384 }
385
386
387 bool font_available(LyXFont const & font)
388 {
389         return fontloader.available(font);
390 }
391
392 namespace {
393
394 extern "C"
395 void C_read_callback(int, void * data)
396 {
397         LyXComm * comm = static_cast<LyXComm *>(data);
398         comm->read_ready();
399 }
400
401 extern "C"
402 void C_datasocket_callback(int, void * data)
403 {
404         LyXDataSocket * client = static_cast<LyXDataSocket *>(data);
405         client->server()->dataCallback(client);
406 }
407
408 extern "C"
409 void C_serversocket_callback(int, void * data)
410 {
411         LyXServerSocket * server = static_cast<LyXServerSocket *>(data);
412         server->serverCallback();
413 }
414
415 }
416
417 void set_read_callback(int fd, LyXComm * comm)
418 {
419         fl_add_io_callback(fd, FL_READ, C_read_callback, comm);
420 }
421
422 void remove_read_callback(int fd)
423 {
424         fl_remove_io_callback(fd, FL_READ, C_read_callback);
425 }
426
427 void set_datasocket_callback(LyXDataSocket * p)
428 {
429         fl_add_io_callback(p->fd(), FL_READ, C_datasocket_callback, p);
430 }
431
432 void remove_datasocket_callback(LyXDataSocket * p)
433 {
434         fl_remove_io_callback(p->fd(), FL_READ, C_datasocket_callback);
435 }
436
437 void set_serversocket_callback(LyXServerSocket * p)
438 {
439         fl_add_io_callback(p->fd(), FL_READ, C_serversocket_callback, p);
440 }
441
442 void remove_serversocket_callback(LyXServerSocket * p)
443 {
444         fl_remove_io_callback(p->fd(), FL_READ, C_serversocket_callback);
445 }
446
447 string const roman_font_name()
448 {
449         return "times";
450 }
451
452
453 string const sans_font_name()
454 {
455         return "helvetica";
456 }
457
458
459 string const typewriter_font_name()
460 {
461         return "courier";
462 }
463
464 }; // namespace lyx_gui