]> git.lyx.org Git - features.git/blob - src/frontends/xforms/lyx_gui.C
the lyxsocket changes
[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(new XFormsView(width, height));
295         LyX::ref().addLyXView(view);
296
297         view->show(xpos, ypos, "LyX");
298         view->init();
299
300         // FIXME: some code below needs moving
301
302         lyxserver = new LyXServer(&view->getLyXFunc(), lyxrc.lyxpipes);
303         lyxsocket = new LyXServerSocket(&view->getLyXFunc(),
304                           os::slashify_path(os::getTmpDir() + "/lyxsocket"));
305
306         vector<string>::const_iterator cit = files.begin();
307         vector<string>::const_iterator end = files.end();
308         for (; cit != end; ++cit)
309                 view->view()->loadLyXFile(*cit, true);
310
311         // handle the batch commands the user asked for
312         if (!batch.empty())
313                 view->getLyXFunc().dispatch(lyxaction.lookupFunc(batch));
314
315         // enter the event loop
316         while (!finished) {
317                 if (fl_check_forms() == FL_EVENT) {
318                         XEvent ev;
319                         fl_XNextEvent(&ev);
320                         lyxerr[Debug::GUI]
321                                 << "Received unhandled X11 event" << endl
322                                 << "Type: " << ev.xany.type
323                                 << " Target: 0x" << hex << ev.xany.window
324                                 << dec << endl;
325                 }
326         }
327
328         // FIXME: breaks emergencyCleanup
329         delete lyxsocket;
330         delete lyxserver;
331 }
332
333
334 void exit()
335 {
336         finished = true;
337 }
338
339
340 void sync_events()
341 {
342         // FIXME
343 }
344
345
346 FuncStatus getStatus(FuncRequest const & /*ev*/)
347 {
348         // Nothing interesting to do here
349         return FuncStatus();
350 }
351
352 string const hexname(LColor_color col)
353 {
354         unsigned int r, g, b;
355         bool const success = getRGBColor(col, r, g, b);
356         if (!success) {
357                 lyxerr << "X can't find color for \"" << lcolor.getLyXName(col)
358                        << '"' << endl;
359                 return string();
360         }
361
362         ostringstream os;
363
364         os << setbase(16) << setfill('0')
365            << setw(2) << r
366            << setw(2) << g
367            << setw(2) << b;
368
369         return os.str();
370 }
371
372
373 void update_color(LColor_color col)
374 {
375         lyxColorHandler->getGCForeground(col);
376         lyxColorHandler->updateColor(col);
377 }
378
379
380 void update_fonts()
381 {
382         fontloader.update();
383 }
384
385
386 bool font_available(LyXFont const & font)
387 {
388         return fontloader.available(font);
389 }
390
391 namespace {
392
393 extern "C"
394 void C_read_callback(int, void * data)
395 {
396         LyXComm * comm = static_cast<LyXComm *>(data);
397         comm->read_ready();
398 }
399
400 }
401
402
403 void set_read_callback(int fd, LyXComm * comm)
404 {
405         fl_add_io_callback(fd, FL_READ, C_read_callback, comm);
406 }
407
408 void remove_read_callback(int fd)
409 {
410         fl_remove_io_callback(fd, FL_READ, C_read_callback);
411 }
412
413
414 namespace {
415
416 std::map<int, boost::function<void()> > socket_callbacks;
417
418 extern "C"
419 void C_socket_callback(int fd, void *)
420 {
421         socket_callbacks[fd]();
422 }
423
424
425 } // NS anon
426
427
428 void register_socket_callback(int fd, boost::function<void()> func)
429 {
430         socket_callbacks[fd] = func;
431         fl_add_io_callback(fd, FL_READ, C_socket_callback, 0);
432 }
433
434
435 void unregister_socket_callback(int fd)
436 {
437         fl_remove_io_callback(fd, FL_READ, C_socket_callback);
438         socket_callbacks.erase(fd);
439 }
440
441
442 string const roman_font_name()
443 {
444         return "times";
445 }
446
447
448 string const sans_font_name()
449 {
450         return "helvetica";
451 }
452
453
454 string const typewriter_font_name()
455 {
456         return "courier";
457 }
458
459 }; // namespace lyx_gui