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