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