]> git.lyx.org Git - features.git/blob - src/frontends/xforms/lyx_gui.C
Move window width/height/posx/posy from frontends to lyx_main.C, from Bo Peng (ben...
[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/package.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::package;
52
53 using lyx::frontend::fontloader;
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 int getDPI()
89 {
90         Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen);
91         return int(((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                 ::exit(1);
182         }
183
184         fcntl(ConnectionNumber(display), F_SETFD, FD_CLOEXEC);
185
186         XSetErrorHandler(LyX_XErrHandler);
187
188         lyxColorHandler.reset(new LyXColorHandler);
189
190         using namespace lyx::graphics;
191
192         // connect the image loader based on the xforms library
193         Image::newImage = boost::bind(&xformsImage::newImage);
194         Image::loadableFormats = boost::bind(&xformsImage::loadableFormats);
195
196         // must do this /before/ lyxrc gets read
197         lyxrc.dpi = getDPI();
198
199         LoaderQueue::setPriority(10,100);
200 }
201
202
203 void parse_lyxrc()
204 {
205         XformsColor::read(addName(package().user_support(),
206                                   "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                 int width, int height, int posx, int posy)
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         lyxerr[Debug::GUI] << "Creating view: " << width << 'x' << height
279                            << '+' << posx << '+' << posy << endl;
280
281         boost::shared_ptr<XFormsView> view(new XFormsView(width, height));
282         LyX::ref().addLyXView(view);
283
284         view->show(posx == -1 ? (WidthOfScreen(s) - width) / 2 : posx, 
285                        posy == -1 ? (HeightOfScreen(s) - height) / 2 : posy, "LyX");
286         view->init();
287
288         // FIXME: some code below needs moving
289
290         lyxserver = new LyXServer(&view->getLyXFunc(), lyxrc.lyxpipes);
291         lyxsocket = new LyXServerSocket(&view->getLyXFunc(),
292                           os::internal_path(package().temp_dir() + "/lyxsocket"));
293
294         for_each(files.begin(), files.end(),
295                 bind(&BufferView::loadLyXFile, view->view(), _1, true));
296
297         // handle the batch commands the user asked for
298         if (!batch.empty())
299                 view->getLyXFunc().dispatch(lyxaction.lookupFunc(batch));
300
301         // enter the event loop
302         while (!finished) {
303                 if (fl_check_forms() == FL_EVENT) {
304                         XEvent ev;
305                         fl_XNextEvent(&ev);
306                         lyxerr[Debug::GUI]
307                                 << "Received unhandled X11 event" << endl
308                                 << "Type: " << ev.xany.type
309                                 << " Target: 0x" << hex << ev.xany.window
310                                 << dec << endl;
311                 }
312         }
313
314         // FIXME: breaks emergencyCleanup
315         delete lyxsocket;
316         delete lyxserver;
317 }
318
319
320 void exit()
321 {
322         finished = true;
323 }
324
325
326 void sync_events()
327 {
328         // FIXME
329 }
330
331
332 FuncStatus getStatus(FuncRequest const & /*ev*/)
333 {
334         // Nothing interesting to do here
335         return FuncStatus();
336 }
337
338
339 bool getRGBColor(LColor_color col, lyx::RGBColor & rgbcol)
340 {
341         string const name = lcolor.getX11Name(col);
342         Display * const display = fl_get_display();
343         Colormap const cmap = fl_state[fl_get_vclass()].colormap;
344         XColor xcol, ccol;
345
346         if (XLookupColor(display, cmap, name.c_str(), &xcol, &ccol) == 0) {
347                 rgbcol.r = 0;
348                 rgbcol.g = 0;
349                 rgbcol.b = 0;
350                 return false;
351         }
352
353         // Note that X stores the RGB values in the range 0 - 65535
354         // whilst we require them in the range 0 - 255.
355         rgbcol.r = xcol.red   / 256;
356         rgbcol.g = xcol.green / 256;
357         rgbcol.b = xcol.blue  / 256;
358         return true;
359 }
360
361
362 string const hexname(LColor_color col)
363 {
364         lyx::RGBColor rgbcol;
365         if (!getRGBColor(col, rgbcol)) {
366                 lyxerr << "X can't find color for \"" << lcolor.getLyXName(col)
367                        << '"' << endl;
368                 return string();
369         }
370
371         ostringstream os;
372
373         os << setbase(16) << setfill('0')
374            << setw(2) << rgbcol.r
375            << setw(2) << rgbcol.g
376            << setw(2) << rgbcol.b;
377
378         return os.str();
379 }
380
381
382 void update_color(LColor_color col)
383 {
384         lyxColorHandler->getGCForeground(col);
385         lyxColorHandler->updateColor(col);
386 }
387
388
389 void update_fonts()
390 {
391         fontloader.update();
392 }
393
394
395 bool font_available(LyXFont const & font)
396 {
397         return fontloader.available(font);
398 }
399
400
401 namespace {
402
403 std::map<int, boost::function<void()> > socket_callbacks;
404
405 extern "C"
406 void C_socket_callback(int fd, void *)
407 {
408         socket_callbacks[fd]();
409 }
410
411
412 } // NS anon
413
414
415 void register_socket_callback(int fd, boost::function<void()> func)
416 {
417         socket_callbacks[fd] = func;
418         fl_add_io_callback(fd, FL_READ, C_socket_callback, 0);
419 }
420
421
422 void unregister_socket_callback(int fd)
423 {
424         fl_remove_io_callback(fd, FL_READ, C_socket_callback);
425         socket_callbacks.erase(fd);
426 }
427
428
429 string const roman_font_name()
430 {
431         return "times";
432 }
433
434
435 string const sans_font_name()
436 {
437         return "helvetica";
438 }
439
440
441 string const typewriter_font_name()
442 {
443         return "courier";
444 }
445
446 }; // namespace lyx_gui