]> git.lyx.org Git - features.git/blob - src/frontends/xforms/lyx_gui.C
change "support/std_sstream.h" to <sstream>
[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 <fcntl.h>
46
47 #include <sstream>
48 #include <iomanip>
49
50 using lyx::support::AddName;
51 using lyx::support::user_lyxdir;
52
53 using lyx::frontend::fontloader;
54 using lyx::frontend::getRGBColor;
55 using lyx::frontend::lyxColorHandler;
56 using lyx::frontend::LyXColorHandler;
57 using lyx::frontend::XformsColor;
58 using lyx::frontend::XFormsView;
59
60 namespace os = lyx::support::os;
61
62 #ifndef CXX_GLOBAL_CSTD
63 using std::exit;
64 #endif
65
66 using std::dec;
67 using std::endl;
68 using std::hex;
69 using std::setbase;
70 using std::setfill;
71 using std::setw;
72 using std::ostringstream;
73 using std::vector;
74 using std::string;
75
76
77 extern BufferList bufferlist;
78
79 // FIXME: wrong place !
80 LyXServer * lyxserver;
81 LyXServerSocket * lyxsocket;
82
83 namespace {
84
85 /// quit lyx
86 bool finished = false;
87
88 /// estimate DPI from X server
89 float getDPI()
90 {
91         Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen);
92         return ((HeightOfScreen(scr) * 25.4 / HeightMMOfScreen(scr)) +
93                 (WidthOfScreen(scr) * 25.4 / WidthMMOfScreen(scr))) / 2;
94 }
95
96
97 /// set default GUI configuration
98 void setDefaults()
99 {
100         FL_IOPT cntl;
101         cntl.buttonFontSize = FL_NORMAL_SIZE;
102         cntl.browserFontSize = FL_NORMAL_SIZE;
103         cntl.labelFontSize = FL_NORMAL_SIZE;
104         cntl.choiceFontSize = FL_NORMAL_SIZE;
105         cntl.inputFontSize = FL_NORMAL_SIZE;
106         cntl.menuFontSize  = FL_NORMAL_SIZE;
107         cntl.borderWidth = -1;
108         cntl.vclass = FL_DefaultVisual;
109         fl_set_defaults(FL_PDVisual
110                         | FL_PDButtonFontSize
111                         | FL_PDBrowserFontSize
112                         | FL_PDLabelFontSize
113                         | FL_PDChoiceFontSize
114                         | FL_PDInputFontSize
115                         | FL_PDMenuFontSize
116                         | FL_PDBorderWidth, &cntl);
117 }
118
119
120 extern "C" {
121
122 int LyX_XErrHandler(Display * display, XErrorEvent * xeev) {
123         // We don't abort on BadWindow
124         if (xeev->error_code == BadWindow) {
125                 lyxerr << "BadWindow received !" << endl;
126                 lyxerr << "If you're using xforms 1.0 or greater, "
127                         << " please report this to lyx-devel@lists.lyx.org" << endl;
128                 return 0;
129         }
130
131         // emergency cleanup
132         LyX::cref().emergencyCleanup();
133
134         // Get the reason for the crash.
135         char etxt[513];
136         XGetErrorText(display, xeev->error_code, etxt, 512);
137         lyxerr << etxt << " id: " << xeev->resourceid << endl;
138         // By doing an abort we get a nice backtrace. (hopefully)
139         lyx::support::abort();
140         return 0;
141 }
142
143 }
144
145 /// read in geometry specification
146 char geometry[40];
147
148 } // namespace anon
149
150
151 namespace lyx_gui {
152
153 bool use_gui = true;
154
155
156 void parse_init(int & argc, char * argv[])
157 {
158         setDefaults();
159
160         FL_CMD_OPT cmdopt[] = {
161                 {"-geometry", "*.geometry", XrmoptionSepArg, "690x510"}
162         };
163
164         FL_resource res[] = {
165                 {"geometry", "geometryClass", FL_STRING, geometry, "", 40}
166         };
167
168         const int num_res = sizeof(res)/sizeof(FL_resource);
169
170         fl_initialize(&argc, argv, "LyX", cmdopt, num_res);
171
172         // It appears that, in xforms >=0.89.5, fl_initialize()
173         // calls setlocale() and ruins our LC_NUMERIC setting.
174         locale_init();
175
176         fl_get_app_resources(res, num_res);
177
178         Display * display = fl_get_display();
179
180         if (!display) {
181                 lyxerr << "LyX: unable to access X display, exiting" << endl;
182                 os::warn("Unable to access X display, exiting");
183                 ::exit(1);
184         }
185
186         fcntl(ConnectionNumber(display), F_SETFD, FD_CLOEXEC);
187
188         XSetErrorHandler(LyX_XErrHandler);
189
190         lyxColorHandler.reset(new LyXColorHandler);
191
192         using namespace lyx::graphics;
193
194         // connect the image loader based on the xforms library
195         Image::newImage = boost::bind(&xformsImage::newImage);
196         Image::loadableFormats = boost::bind(&xformsImage::loadableFormats);
197
198         // must do this /before/ lyxrc gets read
199         lyxrc.dpi = getDPI();
200
201         LoaderQueue::setPriority(10,100);
202 }
203
204
205 void parse_lyxrc()
206 {
207         XformsColor::read(AddName(user_lyxdir(), "preferences.xform"));
208
209         if (lyxrc.popup_font_encoding.empty())
210                 lyxrc.popup_font_encoding = lyxrc.font_norm;
211         // Set the font name for popups and menus
212         string boldfontname = lyxrc.popup_bold_font
213                                + "-*-*-*-?-*-*-*-*-"
214                                + lyxrc.popup_font_encoding;
215                 // "?" means "scale that font"
216         string fontname = lyxrc.popup_normal_font
217                                + "-*-*-*-?-*-*-*-*-"
218                                + lyxrc.popup_font_encoding;
219
220         int bold = fl_set_font_name(FL_BOLD_STYLE, boldfontname.c_str());
221         int normal = fl_set_font_name(FL_NORMAL_STYLE, fontname.c_str());
222         if (bold < 0)
223                 lyxerr << "Could not set menu font to "
224                        << boldfontname << endl;
225
226         if (normal < 0)
227                 lyxerr << "Could not set popup font to "
228                        << fontname << endl;
229
230         if (bold < 0 && normal < 0) {
231                 lyxerr << "Using 'helvetica' font for menus" << endl;
232                 boldfontname = "-*-helvetica-bold-r-*-*-*-?-*-*-*-*-iso8859-1";
233                 fontname = "-*-helvetica-medium-r-*-*-*-?-*-*-*-*-iso8859-1";
234                 bold = fl_set_font_name(FL_BOLD_STYLE, boldfontname.c_str());
235                 normal = fl_set_font_name(FL_NORMAL_STYLE, fontname.c_str());
236
237                 if (bold < 0 && normal < 0) {
238                         lyxerr << "Could not find helvetica font. Using 'fixed'." << endl;
239                         fl_set_font_name(FL_NORMAL_STYLE, "fixed");
240                         normal = bold = 0;
241                 }
242         }
243         if (bold < 0)
244                 fl_set_font_name(FL_BOLD_STYLE, fontname.c_str());
245         else if (normal < 0)
246                 fl_set_font_name(FL_NORMAL_STYLE, boldfontname.c_str());
247
248         fl_setpup_fontstyle(FL_NORMAL_STYLE);
249         fl_setpup_fontsize(FL_NORMAL_SIZE);
250         fl_setpup_color(FL_MCOL, FL_BLACK);
251         fl_set_goodies_font(FL_NORMAL_STYLE, FL_NORMAL_SIZE);
252         fl_set_tooltip_font(FL_NORMAL_STYLE, FL_NORMAL_SIZE);
253 }
254
255
256 void start(string const & batch, vector<string> const & files)
257 {
258         // initial geometry
259         int xpos = -1;
260         int ypos = -1;
261         unsigned int width = 690;
262         unsigned int height = 510;
263
264         int const geometryBitmask =
265                 XParseGeometry(geometry,
266                                &xpos, &ypos, &width, &height);
267
268         // if width is not set by geometry, check it against monitor width
269         if (!(geometryBitmask & WidthValue)) {
270                 Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen);
271                 if (WidthOfScreen(scr) - 8 < int(width))
272                         width = WidthOfScreen(scr) - 8;
273         }
274
275         // if height is not set by geometry, check it against monitor height
276         if (!(geometryBitmask & HeightValue)) {
277                 Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen);
278                 if (HeightOfScreen(scr) - 24 < int(height))
279                         height = HeightOfScreen(scr) - 24;
280         }
281
282         Screen * s = ScreenOfDisplay(fl_get_display(), fl_screen);
283
284         // recalculate xpos if it's not set
285         if (xpos == -1)
286                 xpos = (WidthOfScreen(s) - width) / 2;
287
288         // recalculate ypos if it's not set
289         if (ypos == -1)
290                 ypos = (HeightOfScreen(s) - height) / 2;
291
292         lyxerr[Debug::GUI] << "Creating view: " << width << 'x' << height
293                            << '+' << xpos << '+' << ypos << endl;
294
295         boost::shared_ptr<XFormsView> view(new XFormsView(width, height));
296         LyX::ref().addLyXView(view);
297
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
393 namespace {
394
395 std::map<int, boost::function<void()> > socket_callbacks;
396
397 extern "C"
398 void C_socket_callback(int fd, void *)
399 {
400         socket_callbacks[fd]();
401 }
402
403
404 } // NS anon
405
406
407 void register_socket_callback(int fd, boost::function<void()> func)
408 {
409         socket_callbacks[fd] = func;
410         fl_add_io_callback(fd, FL_READ, C_socket_callback, 0);
411 }
412
413
414 void unregister_socket_callback(int fd)
415 {
416         fl_remove_io_callback(fd, FL_READ, C_socket_callback);
417         socket_callbacks.erase(fd);
418 }
419
420
421 string const roman_font_name()
422 {
423         return "times";
424 }
425
426
427 string const sans_font_name()
428 {
429         return "helvetica";
430 }
431
432
433 string const typewriter_font_name()
434 {
435         return "courier";
436 }
437
438 }; // namespace lyx_gui