source: git/src/aven.cc @ 6f402d7

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-datawalls-data-hanging-as-warning
Last change on this file since 6f402d7 was 30621f5, checked in by Olly Betts <olly@…>, 10 years ago

src/aven.cc: Don't persist full screen mode between runs - it's not a
standard behaviour of desktop programs, and it's too easy to go into
full screen mode from the menu and then not be able to get out again
because you don't know the required key shortcut.

  • Property mode set to 100644
File size: 10.7 KB
Line 
1//
2//  aven.cc
3//
4//  Main class for Aven.
5//
6//  Copyright (C) 2001 Mark R. Shinwell.
7//  Copyright (C) 2002,2003,2004,2005,2006,2011,2013,2014 Olly Betts
8//
9//  This program is free software; you can redistribute it and/or modify
10//  it under the terms of the GNU General Public License as published by
11//  the Free Software Foundation; either version 2 of the License, or
12//  (at your option) any later version.
13//
14//  This program is distributed in the hope that it will be useful,
15//  but WITHOUT ANY WARRANTY; without even the implied warranty of
16//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17//  GNU General Public License for more details.
18//
19//  You should have received a copy of the GNU General Public License
20//  along with this program; if not, write to the Free Software
21//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22//
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include "aven.h"
29#include "log.h"
30#include "mainfrm.h"
31
32#include "cmdline.h"
33#include "message.h"
34#include "useful.h"
35
36#include <assert.h>
37#include <signal.h>
38#include <stdio.h>
39
40#include <wx/confbase.h>
41#include <wx/image.h>
42#if wxUSE_DISPLAY
43// wxDisplay was added in wx 2.5; but it may not be built for mingw (because
44// the header seems to be missing).
45#include <wx/display.h>
46#endif
47
48bool double_buffered = false;
49
50static const struct option long_opts[] = {
51    /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
52    {"survey", required_argument, 0, 's'},
53    {"print", no_argument, 0, 'p'},
54    {"help", no_argument, 0, HLP_HELP},
55    {"version", no_argument, 0, HLP_VERSION},
56    {0, 0, 0, 0}
57};
58
59#define short_opts "s:p"
60
61static struct help_msg help[] = {
62    /*                          <-- */
63    /* TRANSLATORS: --help output for --survey option.
64     *
65     * "this" has been added to English translation */
66    {HLP_ENCODELONG(0),       /*only load the sub-survey with this prefix*/199, 0},
67    /* TRANSLATORS: --help output for aven --print option */
68    {HLP_ENCODELONG(1),       /*print and exit (requires a 3d file)*/119, 0},
69    {0, 0, 0}
70};
71
72#ifdef __WXMSW__
73IMPLEMENT_APP(Aven)
74#else
75IMPLEMENT_APP_NO_MAIN(Aven)
76IMPLEMENT_WX_THEME_SUPPORT
77#endif
78
79Aven::Aven() :
80    m_Frame(NULL), m_pageSetupData(NULL)
81{
82    wxFont::SetDefaultEncoding(wxFONTENCODING_UTF8);
83}
84
85Aven::~Aven()
86{
87    delete m_pageSetupData;
88}
89
90static int getopt_first_response = 0;
91
92static char ** utf8_argv;
93
94#ifdef __WXMSW__
95bool Aven::Initialize(int& my_argc, wxChar **my_argv)
96{
97    // wxWidgets passes us wxChars, which may be wide characters but cmdline
98    // wants UTF-8 so we need to convert.
99    utf8_argv = new char * [my_argc + 1];
100    for (int i = 0; i < my_argc; ++i){
101        utf8_argv[i] = strdup(wxString(my_argv[i]).mb_str());
102    }
103    utf8_argv[my_argc] = NULL;
104
105    msg_init(utf8_argv);
106    select_charset(CHARSET_UTF8);
107    /* Want --version and decent --help output, which cmdline does for us.
108     * wxCmdLine is much less good.
109     */
110    /* TRANSLATORS: Here "survey" is a "cave map" rather than list of questions
111     * - it should be translated to the terminology that cavers using the
112     * language would use.
113     *
114     * Part of aven --help */
115    cmdline_set_syntax_message(/*[SURVEY_FILE]*/269, 0, NULL);
116    cmdline_init(my_argc, utf8_argv, short_opts, long_opts, NULL, help, 0, 1);
117    getopt_first_response = cmdline_getopt();
118    return wxApp::Initialize(my_argc, my_argv);
119}
120#else
121int main(int argc, char **argv)
122{
123#ifdef __WXMAC__
124    // MacOS passes a magic -psn_XXXX command line argument in argv[1] which
125    // wx ignores for us, but in wxApp::Initialize() which hasn't been
126    // called yet.  So we need to remove it ourselves.
127    if (argc > 1 && strncmp(argv[1], "-psn_", 5) == 0) {
128        --argc;
129        memmove(argv + 1, argv + 2, argc * sizeof(char *));
130    }
131#endif
132    // Call msg_init() and start processing the command line first so that
133    // we can respond to --help and --version even without an X display.
134    msg_init(argv);
135    select_charset(CHARSET_UTF8);
136    /* Want --version and decent --help output, which cmdline does for us.
137     * wxCmdLine is much less good.
138     */
139    cmdline_set_syntax_message(/*[SURVEY_FILE]*/269, 0, NULL);
140    cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 0, 1);
141    getopt_first_response = cmdline_getopt();
142
143    utf8_argv = argv;
144
145#if wxUSE_UNICODE
146    wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[0]));
147    wxChar * wargv[2];
148    if (buf) {
149        wargv[0] = wxStrdup(buf);
150    } else {
151        // Eep - couldn't convert the executable's name to wide characters!
152        wargv[0] = wxStrdup(APP_NAME);
153    }
154    wargv[1] = NULL;
155    int wargc = 1;
156    return wxEntry(wargc, wargv);
157#else
158    char *dummy_argv[2] = { argv[0], NULL };
159    int dummy_argc = 1;
160    return wxEntry(dummy_argc, dummy_argv);
161#endif
162}
163#endif
164
165bool Aven::OnInit()
166{
167    wxLog::SetActiveTarget(new MyLogWindow());
168
169    {
170        // Suppress message box warnings about messages not found.
171        wxLogNull logNo;
172        wxLocale *loc = new wxLocale();
173        loc->AddCatalogLookupPathPrefix(wmsg_cfgpth());
174        wxString msg_lang_str(msg_lang, wxConvUTF8);
175        const char *lang = msg_lang2 ? msg_lang2 : msg_lang;
176        wxString lang_str(lang, wxConvUTF8);
177#if wxCHECK_VERSION(2,9,0)
178        loc->Init(msg_lang_str, lang_str, msg_lang_str);
179#else
180        loc->Init(msg_lang_str, lang_str, msg_lang_str, true, true);
181#endif
182        // The existence of the wxLocale object is enough - no need to keep a
183        // pointer to it!
184    }
185
186    wxString survey;
187    bool print_and_exit = false;
188
189    while (true) {
190        int opt;
191        if (getopt_first_response) {
192            opt = getopt_first_response;
193            getopt_first_response = 0;
194        } else {
195            opt = cmdline_getopt();
196        }
197        if (opt == EOF) break;
198        if (opt == 's') {
199            survey = wxString(optarg, wxConvUTF8);
200        }
201        if (opt == 'p') {
202            print_and_exit = true;
203        }
204    }
205
206    if (print_and_exit && !utf8_argv[optind]) {
207        cmdline_syntax(); // FIXME : not a helpful error...
208        exit(1);
209    }
210
211    wxString fnm;
212    if (utf8_argv[optind]) {
213        fnm = wxString(utf8_argv[optind], wxConvUTF8);
214        if (fnm.empty() && *(utf8_argv[optind])) {
215            ReportError(wxT("File argument's filename has bad encoding"));
216            return false;
217        }
218    }
219
220    // Use a double-buffered visual if available, as it will give much smoother
221    // animation.
222    double_buffered = true;
223    int wx_gl_attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 };
224    if (!InitGLVisual(wx_gl_attribs)) {
225        int wx_gl_attribs_no_db[] = { WX_GL_RGBA, 0 };
226        if (!InitGLVisual(wx_gl_attribs_no_db)) {
227            wxString m;
228            /* TRANSLATORS: %s will be replaced with "Aven" currently (and
229             * perhaps by "Survex" or other things in future). */
230            m.Printf(wmsg(/*This version of %s requires OpenGL to work, but it isn’t available.*/405), APP_NAME);
231            wxMessageBox(m, APP_NAME, wxOK | wxCENTRE | wxICON_EXCLAMATION);
232            exit(1);
233        }
234        double_buffered = false;
235    }
236
237    wxImage::AddHandler(new wxPNGHandler);
238
239    // Obtain the screen size.
240    wxPoint pos(wxDefaultPosition);
241    int width, height;
242    wxConfigBase::Get()->Read(wxT("width"), &width, 0);
243    if (width > 0) wxConfigBase::Get()->Read(wxT("height"), &height, 0);
244    // We used to persist full screen mode (-1 was maximized,
245    // -2 full screen), but people would get stuck in full
246    // screen mode, unsure how to exit.
247    bool maximized = (width <= -1);
248    if (width <= 0 || height <= 0) {
249#if wxUSE_DISPLAY
250        wxRect geom = wxDisplay().GetGeometry();
251        pos.x = geom.x;
252        pos.y = geom.y;
253        width = geom.width;
254        height = geom.height;
255#else
256        wxClientDisplayRect(&pos.x, &pos.y, &width, &height);
257        // Crude fix to help behaviour on multi-monitor displays.
258        // Fudge factors are a bit specific to my setup...
259        if (width > height * 3 / 2) {
260            pos.x += width;
261            width = height * 3 / 2;
262            pos.x -= width;
263        }
264#endif
265
266        // Calculate a reasonable size for our window.
267        pos.x += width / 8;
268        pos.y += height / 8;
269        width = width * 3 / 4;
270        height = height * 3 / 4;
271    }
272
273    // Create the main window.
274    m_Frame = new MainFrm(APP_NAME, pos, wxSize(width, height));
275
276    // Select maximised if that's the saved state.
277    if (maximized) {
278        m_Frame->Maximize();
279    }
280
281    if (utf8_argv[optind]) {
282        m_Frame->OpenFile(fnm, survey);
283    }
284
285    if (print_and_exit) {
286        m_Frame->PrintAndExit();
287        return true;
288    }
289
290    m_Frame->Show(true);
291#ifdef _WIN32
292    m_Frame->SetFocus();
293#endif
294    return true;
295}
296
297wxPageSetupDialogData *
298Aven::GetPageSetupDialogData()
299{
300    if (!m_pageSetupData) m_pageSetupData = new wxPageSetupDialogData;
301#ifdef __WXGTK__
302    // Fetch paper margins stored on disk.
303    int left, right, top, bottom;
304    wxConfigBase * cfg = wxConfigBase::Get();
305    // These default margins were chosen by looking at all the .ppd files
306    // on my machine.
307    cfg->Read(wxT("paper_margin_left"), &left, 7);
308    cfg->Read(wxT("paper_margin_right"), &right, 7);
309    cfg->Read(wxT("paper_margin_top"), &top, 14);
310    cfg->Read(wxT("paper_margin_bottom"), &bottom, 14);
311    m_pageSetupData->SetMarginTopLeft(wxPoint(left, top));
312    m_pageSetupData->SetMarginBottomRight(wxPoint(right, bottom));
313#endif
314    return m_pageSetupData;
315}
316
317void
318Aven::SetPageSetupDialogData(const wxPageSetupDialogData & psdd)
319{
320    if (!m_pageSetupData) m_pageSetupData = new wxPageSetupDialogData;
321    *m_pageSetupData = psdd;
322#ifdef __WXGTK__
323    wxPoint topleft = psdd.GetMarginTopLeft();
324    wxPoint bottomright = psdd.GetMarginBottomRight();
325
326    // Store user specified paper margins on disk/in registry.
327    wxConfigBase * cfg = wxConfigBase::Get();
328    cfg->Write(wxT("paper_margin_left"), topleft.x);
329    cfg->Write(wxT("paper_margin_right"), bottomright.x);
330    cfg->Write(wxT("paper_margin_top"), topleft.y);
331    cfg->Write(wxT("paper_margin_bottom"), bottomright.y);
332    cfg->Flush();
333#endif
334}
335
336void Aven::ReportError(const wxString& msg)
337{
338    if (!m_Frame) {
339        wxMessageBox(msg, APP_NAME, wxOK | wxICON_ERROR);
340        return;
341    }
342    AvenAllowOnTop ontop(m_Frame);
343    wxMessageDialog dlg(m_Frame, msg, APP_NAME, wxOK | wxICON_ERROR);
344    dlg.ShowModal();
345}
346
347wxString
348wmsg(int msg_no)
349{
350    return wxString::FromUTF8(msg(msg_no));
351}
352
353const wxString &
354wmsg_cfgpth()
355{
356    static wxString path;
357    if (path.empty())
358        path = wxString(msg_cfgpth(), wxConvUTF8);
359    return path;
360}
361
362// called to report errors by message.c
363extern "C" void
364aven_v_report(int severity, const char *fnm, int line, int en, va_list ap)
365{
366    wxString m;
367    if (fnm) {
368        m = wxString(fnm, wxConvUTF8);
369        if (line) m += wxString::Format(wxT(":%d"), line);
370        m += wxT(": ");
371    }
372
373    if (severity == 0) {
374        m += wmsg(/*warning*/4);
375        m += wxT(": ");
376    }
377
378    char buf[1024];
379    vsnprintf(buf, sizeof(buf), msg(en), ap);
380    m += wxString(buf, wxConvUTF8);
381    if (wxTheApp == NULL) {
382        // We haven't initialised the Aven app object yet.
383        if (!wxInitialize()) {
384            fputs(buf, stderr);
385            PUTC('\n', stderr);
386            exit(1);
387        }
388        wxMessageBox(m, APP_NAME, wxOK | wxICON_ERROR);
389        wxUninitialize();
390    } else {
391        wxGetApp().ReportError(m);
392    }
393}
Note: See TracBrowser for help on using the repository browser.