4 // Main class for Aven.
6 // Copyright (C) 2001 Mark R. Shinwell.
7 // Copyright (C) 2002,2003,2004,2005,2006,2011,2013,2014,2015,2016,2017,2018 Olly Betts
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.
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.
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
28 #define MSG_SETUP_PROJ_SEARCH_PATH 1
42 #include <wx/confbase.h>
45 // wxDisplay was added in wx 2.5; but it may not be built for mingw (because
46 // the header seems to be missing).
47 #include <wx/display.h>
54 static const struct option long_opts
[] = {
55 /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
56 {"survey", required_argument
, 0, 's'},
57 {"print", no_argument
, 0, 'p'},
58 {"help", no_argument
, 0, HLP_HELP
},
59 {"version", no_argument
, 0, HLP_VERSION
},
63 #define short_opts "s:p"
65 static struct help_msg help
[] = {
67 /* TRANSLATORS: --help output for --survey option.
69 * "this" has been added to English translation */
70 {HLP_ENCODELONG(0), /*only load the sub-survey with this prefix*/199, 0},
71 /* TRANSLATORS: --help output for aven --print option */
72 {HLP_ENCODELONG(1), /*print and exit (requires a 3d file)*/119, 0},
79 IMPLEMENT_APP_NO_MAIN(Aven
)
80 IMPLEMENT_WX_THEME_SUPPORT
84 m_Frame(NULL
), m_pageSetupData(NULL
)
86 wxFont::SetDefaultEncoding(wxFONTENCODING_UTF8
);
91 delete m_pageSetupData
;
94 static int getopt_first_response
= 0;
96 static char ** utf8_argv
;
99 bool Aven::Initialize(int& my_argc
, wxChar
**my_argv
)
101 const wxChar
* cmd_line
= GetCommandLineW();
103 // Horrible bodge to handle therion's assumptions about the "Process"
106 // None of these are valid aven command line options, so this is not
107 // going to be triggered accidentally.
108 const wxChar
* p
= wxStrstr(cmd_line
,
109 wxT("aven.exe\" --quiet --log --output="));
111 // Just change the command name in the command line string - that
112 // way the quoting should match what the C runtime expects.
113 wxString
cmd(cmd_line
, p
- cmd_line
);
116 exit(wxExecute(cmd
, wxEXEC_SYNC
));
122 // wxWidgets doesn't split up the command line in the standard way, so
123 // redo it ourselves using the standard API function.
125 // Warning: The returned array from this has no terminating NULL
127 wxChar
** new_argv
= NULL
;
129 new_argv
= CommandLineToArgvW(cmd_line
, &utf8_argc
);
130 bool failed
= (new_argv
== NULL
);
134 FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_FROM_SYSTEM
,
141 wxString m
= "CommandLineToArgvW failed: ";
143 wxMessageBox(m
, APP_NAME
, wxOK
| wxCENTRE
| wxICON_EXCLAMATION
);
149 // Convert wide characters to UTF-8.
150 utf8_argv
= new char * [utf8_argc
+ 1];
151 for (int i
= 0; i
< utf8_argc
; ++i
){
152 utf8_argv
[i
] = strdup(wxString(new_argv
[i
]).utf8_str());
154 utf8_argv
[utf8_argc
] = NULL
;
156 if (!failed
) LocalFree(new_argv
);
160 select_charset(CHARSET_UTF8
);
161 /* Want --version and decent --help output, which cmdline does for us.
162 * wxCmdLine is much less good.
164 /* TRANSLATORS: Here "survey" is a "cave map" rather than list of questions
165 * - it should be translated to the terminology that cavers using the
166 * language would use.
168 * Part of aven --help */
169 cmdline_set_syntax_message(/*[SURVEY_FILE]*/269, 0, NULL
);
170 cmdline_init(utf8_argc
, utf8_argv
, short_opts
, long_opts
, NULL
, help
, 0, 1);
171 getopt_first_response
= cmdline_getopt();
173 // The argc and argv arguments don't actually get used here.
175 return wxApp::Initialize(dummy_argc
, NULL
);
178 int main(int argc
, char **argv
)
181 # if !(wxUSE_GLCANVAS_EGL-0)
182 // The GLX-based wxGLCanvas doesn't work under Wayland, and the code
183 // segfaults: https://trac.wxwidgets.org/ticket/17702
185 // Therefore we force X11 unless we're using the EGL-based wxGLCanvas
186 // (which was added in wxWidgets 3.1.5 and hasn't been backported to
189 // Setting GDK_BACKEND=x11 is the recommended workaround, and it seems to
190 // work to set it here. GTK2 doesn't support Wayland, so doesn't need
192 setenv("GDK_BACKEND", "x11", 1);
197 // MacOS passes a magic -psn_XXXX command line argument in argv[1] which
198 // wx ignores for us, but in wxApp::Initialize() which hasn't been
199 // called yet. So we need to remove it ourselves.
200 if (argc
> 1 && strncmp(argv
[1], "-psn_", 5) == 0) {
202 memmove(argv
+ 1, argv
+ 2, argc
* sizeof(char *));
205 // Call msg_init() and start processing the command line first so that
206 // we can respond to --help and --version even without an X display.
208 select_charset(CHARSET_UTF8
);
209 /* Want --version and decent --help output, which cmdline does for us.
210 * wxCmdLine is much less good.
212 cmdline_set_syntax_message(/*[SURVEY_FILE]*/269, 0, NULL
);
213 cmdline_init(argc
, argv
, short_opts
, long_opts
, NULL
, help
, 0, 1);
214 getopt_first_response
= cmdline_getopt();
219 wxWCharBuffer
buf(wxConvFileName
->cMB2WX(argv
[0]));
222 wargv
[0] = wxStrdup(buf
);
224 // Eep - couldn't convert the executable's name to wide characters!
225 wargv
[0] = wxStrdup(APP_NAME
);
229 return wxEntry(wargc
, wargv
);
231 char *dummy_argv
[2] = { argv
[0], NULL
};
233 return wxEntry(dummy_argc
, dummy_argv
);
240 wxLog::SetActiveTarget(new MyLogWindow());
243 // Suppress message box warnings about messages not found.
245 wxLocale
*loc
= new wxLocale();
246 loc
->AddCatalogLookupPathPrefix(wmsg_cfgpth());
247 wxString
msg_lang_str(msg_lang
, wxConvUTF8
);
248 const char *lang
= msg_lang2
? msg_lang2
: msg_lang
;
249 wxString
lang_str(lang
, wxConvUTF8
);
250 loc
->Init(msg_lang_str
, lang_str
, msg_lang_str
);
251 // The existence of the wxLocale object is enough - no need to keep a
255 const char* opt_survey
= NULL
;
256 bool print_and_exit
= false;
260 if (getopt_first_response
) {
261 opt
= getopt_first_response
;
262 getopt_first_response
= 0;
264 opt
= cmdline_getopt();
266 if (opt
== EOF
) break;
268 if (opt_survey
!= NULL
) {
269 // FIXME: Not a helpful error, but this is temporary until
270 // we actually hook up support for specifying multiple
271 // --survey options properly here.
278 print_and_exit
= true;
282 if (print_and_exit
&& !utf8_argv
[optind
]) {
283 cmdline_syntax(); // FIXME : not a helpful error...
288 if (utf8_argv
[optind
]) {
289 fnm
= wxString(utf8_argv
[optind
], wxConvUTF8
);
290 if (fnm
.empty() && *(utf8_argv
[optind
])) {
291 ReportError(wxT("File argument's filename has bad encoding"));
296 if (!GLACanvas::check_visual()) {
298 /* TRANSLATORS: %s will be replaced with "Aven" currently (and
299 * perhaps by "Survex" or other things in future). */
300 m
.Printf(wmsg(/*This version of %s requires OpenGL to work, but it isn’t available.*/405), APP_NAME
);
301 wxMessageBox(m
, APP_NAME
, wxOK
| wxCENTRE
| wxICON_EXCLAMATION
);
305 wxImage::AddHandler(new wxPNGHandler
);
307 // Obtain the screen geometry.
309 wxRect geom
= wxDisplay().GetGeometry();
312 wxClientDisplayRect(&geom
.x
, &geom
.y
, &geom
.width
, &geom
.height
);
315 wxPoint
pos(wxDefaultPosition
);
317 wxConfigBase::Get()->Read(wxT("width"), &width
, 0);
318 if (width
> 0) wxConfigBase::Get()->Read(wxT("height"), &height
, 0);
319 // We used to persist full screen mode (-1 was maximized,
320 // -2 full screen), but people would get stuck in full
321 // screen mode, unsure how to exit.
322 bool maximized
= (width
<= -1);
323 if (width
<= 0 || height
<= 0) {
327 height
= geom
.height
;
329 // Calculate a reasonable size for our window.
332 width
= width
* 3 / 4;
333 height
= height
* 3 / 4;
335 // Impose a minimum size for sanity, and make sure the window fits on
336 // the display (in case the current display is smaller than the one
337 // in use when the window size was saved). (480x320) is about the
338 // smallest usable size for aven's window.
339 const int min_width
= min(geom
.width
, 480);
340 const int min_height
= min(geom
.height
, 320);
341 if (width
< min_width
|| height
< min_height
) {
342 if (width
< min_width
) {
345 if (height
< min_height
) {
348 pos
.x
= geom
.x
+ (geom
.width
- width
) / 4;
349 pos
.y
= geom
.y
+ (geom
.height
- height
) / 4;
353 // Create the main window.
354 m_Frame
= new MainFrm(APP_NAME
, pos
, wxSize(width
, height
));
356 // Select maximised if that's the saved state.
361 if (utf8_argv
[optind
]) {
362 if (!opt_survey
) opt_survey
= "";
363 m_Frame
->OpenFile(fnm
, wxString(opt_survey
, wxConvUTF8
));
366 if (print_and_exit
) {
367 m_Frame
->PrintAndExit();
378 wxPageSetupDialogData
*
379 Aven::GetPageSetupDialogData()
381 if (!m_pageSetupData
) m_pageSetupData
= new wxPageSetupDialogData
;
383 // Fetch paper margins stored on disk.
384 int left
, right
, top
, bottom
;
385 wxConfigBase
* cfg
= wxConfigBase::Get();
386 // These default margins were chosen by looking at all the .ppd files
388 cfg
->Read(wxT("paper_margin_left"), &left
, 7);
389 cfg
->Read(wxT("paper_margin_right"), &right
, 7);
390 cfg
->Read(wxT("paper_margin_top"), &top
, 14);
391 cfg
->Read(wxT("paper_margin_bottom"), &bottom
, 14);
392 m_pageSetupData
->SetMarginTopLeft(wxPoint(left
, top
));
393 m_pageSetupData
->SetMarginBottomRight(wxPoint(right
, bottom
));
395 return m_pageSetupData
;
399 Aven::SetPageSetupDialogData(const wxPageSetupDialogData
& psdd
)
401 if (!m_pageSetupData
) m_pageSetupData
= new wxPageSetupDialogData
;
402 *m_pageSetupData
= psdd
;
404 wxPoint topleft
= psdd
.GetMarginTopLeft();
405 wxPoint bottomright
= psdd
.GetMarginBottomRight();
407 // Store user specified paper margins on disk/in registry.
408 wxConfigBase
* cfg
= wxConfigBase::Get();
409 cfg
->Write(wxT("paper_margin_left"), topleft
.x
);
410 cfg
->Write(wxT("paper_margin_right"), bottomright
.x
);
411 cfg
->Write(wxT("paper_margin_top"), topleft
.y
);
412 cfg
->Write(wxT("paper_margin_bottom"), bottomright
.y
);
419 Aven::MacOpenFiles(const wxArrayString
& filenames
)
421 if (filenames
.size() != 1) {
422 ReportError(wxT("Aven can only load one file at a time"));
425 m_Frame
->OpenFile(filenames
[0], wxString());
429 Aven::MacPrintFiles(const wxArrayString
& filenames
)
431 if (filenames
.size() != 1) {
432 ReportError(wxT("Aven can only print one file at a time"));
435 m_Frame
->OpenFile(filenames
[0], wxString());
436 m_Frame
->PrintAndExit();
440 void Aven::ReportError(const wxString
& msg
)
443 wxMessageBox(msg
, APP_NAME
, wxOK
| wxICON_ERROR
);
446 wxMessageDialog
dlg(m_Frame
, msg
, APP_NAME
, wxOK
| wxICON_ERROR
);
453 static wxString path
;
455 path
= wxString(msg_cfgpth(), wxConvUTF8
);
459 // called to report errors by message.c
461 aven_v_report(int severity
, const char *fnm
, int line
, int en
, va_list ap
)
465 m
= wxString(fnm
, wxConvUTF8
);
466 if (line
) m
+= wxString::Format(wxT(":%d"), line
);
470 if (severity
== DIAG_WARN
) {
471 m
+= wmsg(/*warning*/4);
476 vsnprintf(buf
, sizeof(buf
), msg(en
), ap
);
477 m
+= wxString(buf
, wxConvUTF8
);
478 if (wxTheApp
== NULL
) {
479 // We haven't initialised the Aven app object yet.
480 if (!wxInitialize()) {
485 wxMessageBox(m
, APP_NAME
, wxOK
| wxICON_ERROR
);
488 wxGetApp().ReportError(m
);