OpenCPN Partial API docs
Loading...
Searching...
No Matches
ocpn_app.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 **************************************************************************/
19
26#include "config.h"
27
28#include <algorithm>
29#include <limits.h>
30#include <memory>
31#include <thread>
32
33#ifdef __WXMSW__
34#include <math.h>
35#include <psapi.h>
36#include <stdlib.h>
37#include <time.h>
38#endif
39
40#ifndef __WXMSW__
41#include <setjmp.h>
42#include <signal.h>
43#endif
44
45#ifdef OCPN_HAVE_X11
46#include <X11/Xatom.h>
47#include <X11/Xlib.h>
48#endif
49
50#ifdef __VISUALC__
51#include <wx/msw/msvcrt.h>
52#endif
53
54#ifdef __MINGW32__
55#undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
56#include <windows.h>
57#endif
58
59#ifdef __WXMSW__
60// #include "c:\\Program Files\\visual leak detector\\include\\vld.h"
61#endif
62
63#if defined(__WXMSW__) && defined(__MSVC__LEAK)
64#include "Stackwalker.h"
65#endif
66
67#include <wx/wxprec.h>
68
69#ifndef WX_PRECOMP
70#include <wx/wx.h>
71#endif // precompiled headers
72
73#include <wx/apptrait.h>
74#include <wx/arrimpl.cpp>
75#include <wx/artprov.h>
76#include <wx/aui/aui.h>
77#include <wx/aui/dockart.h>
78#include <wx/clrpicker.h>
79#include <wx/cmdline.h>
80#include <wx/dialog.h>
81#include <wx/dialog.h>
82#include <wx/dir.h>
83#include <wx/display.h>
84#include <wx/dynlib.h>
85#include <wx/image.h>
86#include <wx/intl.h>
87#include <wx/ipc.h>
88#include <wx/jsonreader.h>
89#include <wx/listctrl.h>
90#include <wx/power.h>
91#include <wx/printdlg.h>
92#include <wx/print.h>
93#include <wx/progdlg.h>
94#include <wx/settings.h>
95#include <wx/stdpaths.h>
96#include <wx/tokenzr.h>
97
98#include "model/ais_decoder.h"
100#include "model/certificates.h"
101#include "model/cmdline.h"
102#include "model/comm_bridge.h"
104#include "model/comm_vars.h"
105#include "model/config_vars.h"
106#include "model/gui_vars.h"
107#include "model/instance_check.h"
108#include "model/local_api.h"
109#include "model/logger.h"
110#include "model/mdns_query.h"
111#include "model/mdns_service.h"
112#include "model/multiplexer.h"
113#include "model/navobj_db.h"
114#include "model/nav_object_database.h"
115#include "model/navutil_base.h"
117#include "model/own_ship.h"
118#include "model/plugin_handler.h"
119#include "model/route.h"
120#include "model/routeman.h"
121#include "model/select.h"
122#include "model/track.h"
123
124#include "about_frame_impl.h"
125#include "about.h"
126#include "ais_info_gui.h"
127#include "ais_target_alert_dlg.h"
128#include "ais_target_list_dlg.h"
129#include "ais_target_query_dlg.h"
130#include "canvas_config.h"
131#include "chartdb.h"
132#include "chcanv.h"
133#include "cm93.h"
134#include "concanv.h"
135#include "config.h"
136#include "config_mgr.h"
137#include "detail_slider.h"
138#include "dychart.h"
139#include "font_mgr.h"
140#include "gdal/cpl_csv.h"
141#include "gl_tex_cache.h"
142#include "go_to_position_dlg.h"
143#include "layer.h"
144#include "mark_info.h"
145#include "navutil.h"
146#include "observable.h"
147#include "ocpn_app.h"
148#include "ocpn_aui_manager.h"
149#include "ocpn_frame.h"
150#include "ocpn_platform.h"
151#include "o_senc.h"
152#include "options.h"
153#include "rest_server_gui.h"
154#include "route_ctx_factory.h"
155#include "routemanagerdialog.h"
156#include "routeman_gui.h"
157#include "route_prop_dlg_impl.h"
158#include "s52plib.h"
159#include "s57chart.h"
160#include "s57_query_dlg.h"
161#include "safe_mode_gui.h"
162#include "SoundFactory.h"
163#include "std_filesystem.h"
164#include "styles.h"
165#include "tcmgr.h"
166#include "thumbwin.h"
167#include "track_prop_dlg.h"
168#include "udev_rule_mgr.h"
169#include "wiz_ui.h"
170
171#ifdef ocpnUSE_GL
172#include "gl_chart_canvas.h"
173#endif
174
175#ifdef __WXOSX__
176#include "model/macutils.h"
177#endif
178
179#ifdef __WXMSW__
180#include "model/garmin_protocol_mgr.h" // Used for port probing on Windows
181void RedirectIOToConsole();
182#endif
183
184#ifdef LINUX_CRASHRPT
185#include "crashprint.h"
186#endif
187
188#ifdef __WXOSX__
189#include "model/macutils.h"
190#endif
191
192#ifdef __ANDROID__
193#include "androidUTIL.h"
194#else
195#include "serial/serial.h"
196#endif
197
198using namespace std::literals::chrono_literals;
199
200const char *const kUsage =
201 R"(Usage:
202 opencpn -h | --help
203 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
204 opencpn --remote [-R] | -q] | -e] |-o <str>]
205
206Options for starting opencpn
207
208 -c, --configdir=<dirpath> Use alternative configuration directory.
209 -p, --portable Run in portable mode.
210 -f, --fullscreen Switch to full screen mode on start.
211 -G, --no_opengl Disable OpenGL video acceleration. This setting will
212 be remembered.
213 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
214 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
215 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
216 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
217 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
218 Zero or negative <num> specifies no limit.
219 -U, --unit_test_2
220 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
221 -W, --config_wizard Start with initial configuration wizard
222
223Options manipulating already started opencpn
224 -r, --remote Execute commands on already running instance
225 -R, --raise Make running OpenCPN visible if hidden
226 -q, --quit Terminate already running opencpn
227 -e, --get_rest_endpoint Print rest server endpoint and exit.
228 -o, --open=<GPX file> Open file in running opencpn
229
230Arguments:
231 GPX file GPX-formatted file with waypoints or routes.
232)";
233
234// comm event definitions
235wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
236wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
237
238wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
239wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
240wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
241wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
242wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
243wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
244wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
245wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
246wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
247
248//------------------------------------------------------------------------------
249// Fwd Declarations
250//------------------------------------------------------------------------------
251
252//------------------------------------------------------------------------------
253// Static variable definition
254//------------------------------------------------------------------------------
255
256WX_DEFINE_OBJARRAY(ArrayOfCDI);
257
258static int user_user_id;
259static int file_user_id;
260
261static int g_mem_total, g_mem_initial;
262
263static unsigned int malloc_max;
264
265static int osMajor, osMinor;
266
267static bool g_bHasHwClock;
268
269#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
270// FIXME (leamas) find a new home
271wxLocale *plocale_def_lang = 0;
272#endif
273
274#ifdef LINUX_CRASHRPT
275static wxCrashPrint g_crashprint;
276#endif
277
278#ifndef __WXMSW__
279extern sigjmp_buf env; // the context saved by sigsetjmp();
280#endif // FIXME (leamas) Use exceptions
281
282// {2C9C45C2-8E7D-4C08-A12D-816BBAE722C0}
283#ifdef __WXMSW__
284DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
285 0x6b, 0xba, 0xe7, 0x22, 0xc0);
286#endif
287
288#if !defined(NAN)
289static const long long lNaN = 0xfff8000000000000;
290#define NAN (*(double *)&lNaN)
291#endif
292
293// Some static helpers
294void appendOSDirSlash(wxString *pString);
295
296void InitializeUserColors();
297void DeInitializeUserColors();
298void SetSystemColors(ColorScheme cs);
299
300static bool LoadAllPlugIns(bool load_enabled) {
301 g_Platform->ShowBusySpinner();
302 bool b = PluginLoader::GetInstance()->LoadAllPlugIns(load_enabled);
303 g_Platform->HideBusySpinner();
304 return b;
305}
306
307//------------------------------------------------------------------------------
308// PNG Icon resources
309//------------------------------------------------------------------------------
310
311#if defined(__WXGTK__) || defined(__WXQT__)
312#include "bitmaps/opencpn.xpm"
313#endif
314
315wxString newPrivateFileName(wxString, const char *name,
316 [[maybe_unused]] const char *windowsName) {
317 wxString fname = wxString::FromUTF8(name);
318 wxString filePathAndName;
319
320 filePathAndName = g_Platform->GetPrivateDataDir();
321 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
322 filePathAndName.Append(wxFileName::GetPathSeparator());
323
324#ifdef __WXMSW__
325 wxString fwname = wxString::FromUTF8(windowsName);
326 filePathAndName.Append(fwname);
327#else
328 filePathAndName.Append(fname);
329#endif
330
331 return filePathAndName;
332}
333
334// `Main program` equivalent, creating windows and returning main app frame
335//------------------------------------------------------------------------------
336// MyApp
337//------------------------------------------------------------------------------
338IMPLEMENT_APP(MyApp)
339
340BEGIN_EVENT_TABLE(MyApp, wxApp)
341EVT_ACTIVATE_APP(MyApp::OnActivateApp)
342END_EVENT_TABLE()
343
344static void ActivateRoute(const std::string &guid) {
345 Route *route = g_pRouteMan->FindRouteByGUID(guid);
346 if (!route) {
347 wxLogMessage("Cannot activate guid: no such route");
348 return;
349 }
350 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
351 // If this is an auto-created MOB route, always select the second point
352 // (the MOB)
353 // as the destination.
354 RoutePoint *point;
355 if (wxNOT_FOUND == route->m_RouteNameString.Find("MOB")) {
356 point = g_pRouteMan->FindBestActivatePoint(route, gLat, gLon, gCog, gSog);
357 } else {
358 point = route->GetPoint(2);
359 }
360 g_pRouteMan->ActivateRoute(route, point);
362 route->m_bRtIsSelected = false;
363}
364
365static void ReverseRoute(const std::string &guid) {
366 Route *route = g_pRouteMan->FindRouteByGUID(guid);
367 if (!route) {
368 wxLogMessage("Cannot activate guid: no such route");
369 return;
370 }
371 route->Reverse();
373}
374
375void MyApp::InitRestListeners() {
376 auto activate_route = [&](wxCommandEvent ev) {
377 auto guid = ev.GetString().ToStdString();
378 ActivateRoute(guid);
379 };
380 rest_activate_listener.Init(m_rest_server.activate_route, activate_route);
381 auto reverse_route = [&](wxCommandEvent ev) {
382 auto guid = ev.GetString().ToStdString();
383 ReverseRoute(guid);
384 };
385 rest_reverse_listener.Init(m_rest_server.reverse_route, reverse_route);
386}
387
388bool MyApp::OpenFile(const std::string &path) {
389 NavObjectCollection1 nav_objects;
390 auto result = nav_objects.load_file(path.c_str());
391 if (!result) {
392 std::string s(_("Cannot load route or waypoint file: "));
393 s += std::string("\"") + path + "\"";
394 wxMessageBox(s, "OpenCPN", wxICON_WARNING | wxOK);
395 return false;
396 }
397
398 int wpt_dups;
399 // Import with full vizibility of names and objects
400 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups, true);
401
402 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
403 pRouteManagerDialog->UpdateLists();
404 LLBBox box = nav_objects.GetBBox();
405 if (box.GetValid()) {
406 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
407 }
408 return true;
409}
410
411#ifndef __ANDROID__
412void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
413 // Add OpenCPN specific command line options. Help message
414 // is hardcoded in kUsage;
415 parser.AddSwitch("h", "help", "", wxCMD_LINE_OPTION_HELP);
416 parser.AddSwitch("p", "portable");
417 parser.AddOption("c", "configdir", "", wxCMD_LINE_VAL_STRING,
418 wxCMD_LINE_PARAM_OPTIONAL);
419 parser.AddSwitch("f", "fullscreen");
420 parser.AddSwitch("G", "no_opengl");
421 parser.AddSwitch("W", "config_wizard");
422 parser.AddSwitch("g", "rebuild_gl_raster_cache");
423 parser.AddSwitch("D", "rebuild_chart_db");
424 parser.AddSwitch("P", "parse_all_enc");
425 parser.AddOption("l", "loglevel");
426 parser.AddOption("u", "unit_test_1", "", wxCMD_LINE_VAL_NUMBER);
427 parser.AddSwitch("U", "unit_test_2");
428 parser.AddParam("import GPX files", wxCMD_LINE_VAL_STRING,
429 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
430 parser.AddSwitch("s", "safe_mode");
431 parser.AddSwitch("r", "remote");
432 parser.AddSwitch("R", "raise");
433 parser.AddSwitch("q", "quit");
434 parser.AddSwitch("e", "get_rest_endpoint");
435 parser.AddOption("o", "open", "", wxCMD_LINE_VAL_STRING,
436 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
437}
438#endif // __ANDROID__
439
441#ifdef __ANDROID__
442static void ParseLoglevel(wxCmdLineParser &parser) {
443 wxLog::SetLogLevel(wxLOG_Message);
444}
445#else
446static void ParseLoglevel(wxCmdLineParser &parser) {
447 const char *strLevel = std::getenv("OPENCPN_LOGLEVEL");
448 strLevel = strLevel ? strLevel : "info";
449 wxString wxLevel;
450 if (parser.Found("l", &wxLevel)) {
451 strLevel = wxLevel.c_str();
452 }
453 wxLogLevel level = OcpnLog::str2level(strLevel);
454 if (level == OcpnLog::LOG_BADLEVEL) {
455 fprintf(stderr, "Bad loglevel %s, using \"info\"", strLevel);
456 level = wxLOG_Info;
457 }
458 wxLog::SetLogLevel(level);
459}
460#endif // __ANDROID__
461
462#ifndef __ANDROID__
463bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
464 std::cout << kUsage;
465 return false;
466}
467#endif
468
469#ifndef __ANDROID__
470bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
471 long number;
472 wxString repo;
473 wxString plugin;
474
475 g_unit_test_2 = parser.Found("unit_test_2");
476 g_bportable = parser.Found("p");
477 g_start_fullscreen = parser.Found("fullscreen");
478 g_bdisable_opengl = parser.Found("no_opengl");
479 g_rebuild_gl_cache = parser.Found("rebuild_gl_raster_cache");
480 g_NeedDBUpdate = parser.Found("rebuild_chart_db") ? 2 : 0;
481 g_parse_all_enc = parser.Found("parse_all_enc");
482 g_config_wizard = parser.Found("config_wizard");
483 if (parser.Found("unit_test_1", &number)) {
484 g_unit_test_1 = static_cast<int>(number);
485 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
486 }
487 safe_mode::set_mode(parser.Found("safe_mode"));
488 ParseLoglevel(parser);
489 wxString wxstr;
490 if (parser.Found("configdir", &wxstr)) {
491 g_configdir = wxstr.ToStdString();
492 fs::path path(g_configdir);
493 if (!fs::exists(path) || !fs::is_directory(path)) {
494 std::cerr << g_configdir << " is not an existing directory.\n";
495 return false;
496 }
497 }
498
499 bool has_start_options = false;
500 static const std::vector<std::string> kStartOptions = {
501 "unit_test_2",
502 "p",
503 "fullscreen",
504 "no_opengl",
505 "rebuild_gl_raster_cache",
506 "rebuild_chart_db",
507 "parse_all_enc",
508 "unit_test_1",
509 "safe_mode",
510 "loglevel"};
511 for (const auto &opt : kStartOptions) {
512 if (parser.Found(opt)) has_start_options = true;
513 }
514 if (has_start_options && parser.Found("remote")) {
515 std::cerr << "this option is not compatible with --remote\n";
516 return false;
517 }
518
519 bool has_remote_options = false;
520 static const std::vector<std::string> kRemoteOptions = {
521 "raise", "quit", "open", "get_rest_endpoint"};
522 for (const auto &opt : kRemoteOptions) {
523 if (parser.Found(opt)) has_remote_options = true;
524 }
525 if (has_remote_options && !parser.Found("remote")) {
526 std::cerr << "This option requires --remote\n";
527 return false;
528 }
529
530 for (size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
531 g_params.push_back(parser.GetParam(paramNr).ToStdString());
532
533 wxString optarg;
534 if (!parser.Found("remote"))
535 m_parsed_cmdline = ParsedCmdline();
536 else if (parser.Found("raise"))
537 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
538 else if (parser.Found("quit"))
539 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
540 else if (parser.Found("get_rest_endpoint"))
541 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
542 else if (parser.Found("open", &optarg))
543 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
544 else if (parser.GetParamCount() == 1)
545 m_parsed_cmdline =
546 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
547 else if (!has_start_options && !has_remote_options) {
548 // Neither arguments nor options
549 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
550 }
551 return true;
552}
553#endif // __ANDROID__
554
555#ifdef __WXMSW__
556// Handle any exception not handled by CrashRpt
557// Most probable: Malloc/new failure
558
559bool MyApp::OnExceptionInMainLoop() {
560 wxLogWarning("Caught MainLoopException, continuing...");
561 return true;
562}
563#endif
564
565void MyApp::OnActivateApp(wxActivateEvent &event) { return; }
566
567static wxStopWatch init_sw;
568
569int MyApp::OnRun() {
570 if (m_exitcode != -2) return m_exitcode;
571 return wxAppConsole::OnRun();
572}
573
574MyApp::MyApp()
575 : m_checker(InstanceCheck::GetInstance()),
576 m_rest_server(PINCreateDialog::GetDlgCtx(), RouteCtxFactory(),
577 g_bportable),
578 m_usb_watcher(UsbWatchDaemon::GetInstance()),
579 m_exitcode(-2) {
580#ifdef __linux__
581 // Handle e. g., wayland default display -- see #1166.
582 if (!wxGetEnv("OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
583 if (wxGetEnv("WAYLAND_DISPLAY", NULL)) {
584 setenv("GDK_BACKEND", "x11", 1);
585 }
586 }
587 setenv(
588 "mesa_glthread", "false",
589 1); // Explicitly disable glthread. This may have some impact on OpenGL
590 // performance, but we know it is problematic for us. See #2889
591#endif // __linux__
592}
593
594bool MyApp::OnInit() {
595 if (!wxApp::OnInit()) return false;
596#ifdef __ANDROID__
597 androidEnableBackButton(false);
598 androidEnableOptionItems(false);
599#endif
600
602
603#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
604 // There is a race condition between cairo which is used for text rendering
605 // by gtk and EGL which without the below code causes a bus error and the
606 // program aborts before startup
607 // this hack forces cairo to load right now by rendering some text
608
609 wxBitmap bmp(10, 10, -1);
610 wxMemoryDC dc;
611 dc.SelectObject(bmp);
612 dc.DrawText("X", 0, 0);
613#endif
614
615 // Instantiate the global OCPNPlatform class
616 g_Platform = new OCPNPlatform;
617 g_BasePlatform = g_Platform;
618#ifndef __ANDROID__
619 // We allow only one instance unless the portable option is used
620 if (!g_bportable && wxDirExists(g_Platform->GetPrivateDataDir())) {
621 m_checker.WaitUntilValid();
622 if (m_checker.IsMainInstance()) {
623 // Server is created on first call to GetInstance()
624 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
625 // Server starts running when referenced.
626 [[maybe_unused]] auto &server = LocalServerApi::GetInstance();
627 } else {
628 std::cerr << "No remote opencpn found. Giving up.\n";
629 m_exitcode = 1;
630 return true;
631 }
632 } else {
633 std::unique_ptr<LocalClientApi> client;
634 try {
635 client = LocalClientApi::GetClient();
636 } catch (LocalApiException &ie) {
637 WARNING_LOG << "Ipc client exception: " << ie.str();
638 // If we get here it means that the instance_chk found another
639 // running instance. But that instance is for some reason not
640 // reachable. The safe thing to do is delete the lockfile and exit.
641 // Next start will proceed normally. This may leave a zombie OpenCPN,
642 // but at least O starts.
643 m_checker.CleanUp();
644 wxMessageBox(_("Sorry, an existing instance of OpenCPN may be too busy "
645 "to respond.\nPlease retry."),
646 "OpenCPN", wxICON_INFORMATION | wxOK);
647 m_exitcode = 2;
648 return true; // main program quiet exit.
649 }
650 if (client) {
651 auto result = client->HandleCmdline(m_parsed_cmdline.action,
652 m_parsed_cmdline.arg);
653 if (result.first) {
654 m_exitcode = 0;
655 } else {
656 wxLogDebug("Error running remote command: %s", result.second.c_str());
657 m_exitcode = 1;
658 }
659 return true;
660 }
661 }
662 }
663#endif // __ANDROID__
664
665 if (getenv("OPENCPN_FATAL_ERROR") != 0) {
666 wxLogFatalError(getenv("OPENCPN_FATAL_ERROR"));
667 }
668
669#ifndef __ANDROID__
670 // Check if last run failed, set up safe_mode.
671 if (!safe_mode::get_mode()) {
673 }
674#endif
675
676 // Perform first stage initialization
677 OCPNPlatform::Initialize_1();
678
679 // Set the name of the app as displayed to the user.
680 // This is necessary at least on OS X, for the capitalisation to be correct in
681 // the system menus.
682 MyApp::SetAppDisplayName("OpenCPN");
683
684 // Seed the random number generator
685 wxDateTime x = wxDateTime::UNow();
686 long seed = x.GetMillisecond();
687 seed *= x.GetTicks();
688 srand(seed);
689
690 // Fulup: force floating point to use dot as separation.
691 // This needs to be set early to catch numerics in config file.
692 setlocale(LC_NUMERIC, "C");
693
694 g_start_time = wxDateTime::Now();
695
696 g_loglast_time = g_start_time;
697 g_loglast_time.MakeGMT();
698 g_loglast_time.Subtract(
699 wxTimeSpan(0, 29, 0, 0)); // give 1 minute for GPS to get a fix
700
701 AnchorPointMinDist = 5.0;
702
703 // Init the private memory manager
704 malloc_max = 0;
705
706 // Record initial memory status
707 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
708
709 // Set up default FONT encoding, which should have been done by wxWidgets some
710 // time before this......
711 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
712 wxFONTWEIGHT_NORMAL, FALSE, wxString(""),
713 wxFONTENCODING_SYSTEM);
714 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
715
716 // Start the Notification Manager and remove old persisted messages
717 auto &noteman = NotificationManager::GetInstance();
718 noteman.ScrubNotificationDirectory(30);
719
720 // Establish Log File location
721 if (!g_Platform->InitializeLogFile()) {
722 return false;
723 };
724
725#ifdef __WXMSW__
726
727 // Un-comment the following to establish a separate console window as a
728 // target for printf() in Windows RedirectIOToConsole();
729
730#endif
731
732 // Send init message
733 wxLogMessage("\n\n________\n");
734
735 wxDateTime now = wxDateTime::Now();
736 LOG_INFO("------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
737 now.FormatISODate().mb_str().data());
738 wxLogLevel level = wxLog::GetLogLevel();
739 LOG_INFO("Using loglevel %s", OcpnLog::level2str(level).c_str());
740
741 wxString wxver(wxVERSION_STRING);
742 wxver.Prepend("wxWidgets version: ");
743
744 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
745
746 wxString os_name;
747#ifndef __ANDROID__
748 os_name = platforminfo.GetOperatingSystemIdName();
749#else
750 os_name = platforminfo.GetOperatingSystemFamilyName();
751#endif
752
753 wxString platform = os_name + " " + platforminfo.GetArchName() + " " +
754 platforminfo.GetPortIdName();
755
756 wxLogMessage(wxver + " " + platform);
757
758 ::wxGetOsVersion(&osMajor, &osMinor);
759 wxString osVersionMsg;
760 osVersionMsg.Printf("OS Version reports as: %d.%d", osMajor, osMinor);
761 wxLogMessage(osVersionMsg);
762
763 wxLogMessage("MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
764 g_mem_total / 1024, g_mem_initial / 1024);
765
766 OCPN_OSDetail *detail = g_Platform->GetOSDetail();
767 wxString msgplat;
768 wxString like0;
769 if (!detail->osd_names_like.empty())
770 like0 = detail->osd_names_like[0].c_str();
771 msgplat.Printf("OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
772 detail->osd_arch.c_str(), detail->osd_name.c_str(),
773 detail->osd_version.c_str(), detail->osd_ID.c_str(),
774 like0.mb_str());
775 wxLogMessage(msgplat);
776
777 wxString imsg = "SData_Locn is ";
778 imsg += g_Platform->GetSharedDataDir();
779 wxLogMessage(imsg);
780
781 // Initialize embedded PNG icon graphics
782 ::wxInitAllImageHandlers();
783
784#ifdef __WXQT__
785 // Now we can configure the Qt StyleSheets, if present
786 prepareAndroidStyleSheets();
787#endif
788
789 // Create some static strings
790 pInit_Chart_Dir = new wxString();
791
792 // Establish an empty ChartCroupArray
793 g_pGroupArray = new ChartGroupArray;
794
795 imsg = "PrivateDataDir is ";
796 imsg += g_Platform->GetPrivateDataDir();
797 wxLogMessage(imsg);
798
799 // Create an array string to hold repeating messages, so they don't
800 // overwhelm the log
801 navutil::InitGlobals();
802
803 // Init the Route Manager
805 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
806
807 // Init the Selectable Route Items List
808 pSelect = new Select();
809 pSelect->SetSelectPixelRadius(12);
810
811 // Init the Selectable Tide/Current Items List
812 pSelectTC = new Select();
813 // Increase the select radius for tide/current stations
814 pSelectTC->SetSelectPixelRadius(25);
815
816 // Init the Selectable AIS Target List
817 pSelectAIS = new Select();
818 pSelectAIS->SetSelectPixelRadius(12);
819
820 // Initially AIS display is always on
821 g_bShowAIS = true;
822 g_pais_query_dialog_active = NULL;
823
824 // Who am I?
825 g_hostname = ::wxGetHostName();
826 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
827#ifdef __ANDROID__
828 androidGetDeviceInfo();
829 g_hostname = wxString("Android-") + g_android_Device_Model;
830 g_hostname.Replace(" ", "-", true);
831#endif
832
833 // A Portabel need a unique mDNS data hostname to share routes.
834 if (g_bportable) {
835 wxString p("Portable-");
836 g_hostname = p + g_hostname;
837 }
838
839 // Initialize some lists
840 // Layers
841 pLayerList = new LayerList;
842 // Routes
843 pRouteList = new RouteList;
844
845 // Initialize the NavObj_db
846 auto &navobj_db = NavObj_dB::GetInstance();
847
848 // (Optionally) Capture the user and file(effective) ids
849 // Some build environments may need root privileges for hardware
850 // port I/O, as in the NMEA data input class. Set that up here.
851
852#ifndef __WXMSW__
853#ifdef PROBE_PORTS__WITH_HELPER
854 user_user_id = getuid();
855 file_user_id = geteuid();
856#endif
857#endif
858
859 bool b_initial_load = false;
860
861 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
862 if (config_test_file_name.FileExists())
863 wxLogMessage("Using existing Config_File: " +
864 g_Platform->GetConfigFileName());
865 else {
866 {
867 wxLogMessage("Creating new Config_File: " +
868 g_Platform->GetConfigFileName());
869
870 b_initial_load = true;
871
872 if (true !=
873 config_test_file_name.DirExists(config_test_file_name.GetPath()))
874 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
875 wxLogMessage("Cannot create config file directory for " +
876 g_Platform->GetConfigFileName());
877 }
878 }
879
880 // Open/Create the Config Object
881 pConfig = g_Platform->GetConfigObject();
882 InitBaseConfig(pConfig);
883 pConfig->LoadMyConfig();
884
885 // Override for some safe and nice default values if the config file was
886 // created from scratch
887 if (b_initial_load) g_Platform->SetDefaultOptions();
888
889 g_Platform->applyExpertMode(g_bUIexpert);
890
891 // Now initialize UI Style.
892 g_StyleManager = new ocpnStyle::StyleManager();
893
894 // if(g_useMUI)
895 // g_uiStyle = "MUI_flat";
896
897 g_StyleManager->SetStyle("MUI_flat");
898 if (!g_StyleManager->IsOK()) {
899 wxString msg = _("Failed to initialize the user interface. ");
900 msg << _("OpenCPN cannot start. ");
901 msg << _("The necessary configuration files were not found. ");
902 msg << _("See the log file at ") << g_Platform->GetLogFileName()
903 << _(" for details.") << "\n\n";
904 msg << g_Platform->GetSharedDataDir();
905
906 wxMessageDialog w(NULL, msg, _("Failed to initialize the user interface. "),
907 wxCANCEL | wxICON_ERROR);
908 w.ShowModal();
909 exit(EXIT_FAILURE);
910 }
911
912 if (g_useMUI) {
913 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
914 if (style) style->chartStatusWindowTransparent = true;
915 }
916
917 // Init the WayPoint Manager
918 pWayPointMan = NULL;
919
920 g_display_size_mm = wxMax(50, g_Platform->GetDisplaySizeMM());
921 wxString msg;
922 msg.Printf("Detected display size (horizontal): %d mm",
923 (int)g_display_size_mm);
924 wxLogMessage(msg);
925
926 // User override....
927 if (g_config_display_size_manual &&
931 wxString msg;
932 msg.Printf("Display size (horizontal) config override: %d mm",
933 (int)g_display_size_mm);
934 wxLogMessage(msg);
936 }
937
939
940 if (g_btouch) {
941 int SelectPixelRadius = 50;
942
943 pSelect->SetSelectPixelRadius(SelectPixelRadius);
944 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
945 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
946 }
947
948 // Is this the first run after a clean installation?
949 if (!n_NavMessageShown) {
950 g_bFirstRun = true;
951 }
952
953 // Now we can set the locale
954 // using wxWidgets/gettext methodology....
955
956#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
957
958 // Where are the opencpn.mo files?
959 g_Platform->SetLocaleSearchPrefixes();
960
961 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
962
963 imsg = "System default Language: " + def_lang_canonical;
964 wxLogMessage(imsg);
965
966 wxString cflmsg = "Config file language: " + g_locale;
967 wxLogMessage(cflmsg);
968
969 if (g_locale.IsEmpty()) {
970 g_locale = def_lang_canonical;
971 cflmsg = "Config file language empty, using system default: " + g_locale;
972 wxLogMessage(cflmsg);
973 }
974
975 // Make any adjustments necessary
976 g_locale = g_Platform->GetAdjustedAppLocale();
977 cflmsg = "Adjusted App language: " + g_locale;
978 wxLogMessage(cflmsg);
979
980 // Set the desired locale
981 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
982
983 imsg = "Opencpn language set to: ";
984 imsg += g_locale;
985 wxLogMessage(imsg);
986
987 // French language locale is assumed to include the AZERTY keyboard
988 // This applies to either the system language, or to OpenCPN language
989 // selection
990 if (g_locale == "fr_FR") g_b_assume_azerty = true;
991#else
992 wxLogMessage("wxLocale support not available");
993#endif
994
995#ifndef __ANDROID__
996 // Now that locale is established, possibly run the startup wizard.
997 if (g_config_wizard || b_initial_load) {
998 FirstUseWizImpl wiz(gFrame, pConfig);
999 auto res = wiz.Run();
1000 if (res) {
1001 g_NeedDBUpdate = 2;
1002 }
1003 }
1004#endif
1005
1006 // Instantiate and initialize the Config Manager
1007 ConfigMgr::Get();
1008
1009 // Is this an upgrade?
1010 wxString vs = wxString("Version ") + VERSION_FULL + " Build " + VERSION_DATE;
1011 g_bUpgradeInProcess = (vs != g_config_version_string);
1012
1013 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1014
1015 // log deferred log restart message, if it exists.
1016 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1017 wxLogMessage(g_Platform->GetLargeLogMessage());
1018 }
1019
1020 // Validate OpenGL functionality, if selected
1021#ifndef ocpnUSE_GL
1022 g_bdisable_opengl = true;
1023 ;
1024#endif
1025
1026 if (g_bdisable_opengl) g_bopengl = false;
1027
1028#if defined(__linux__) && !defined(__ANDROID__)
1029 if (g_bSoftwareGL) {
1030 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
1031 }
1032#endif
1033
1034 // FIXMW (dave) move to frame
1035 // g_bTransparentToolbarInOpenGLOK = isTransparentToolbarInOpenGLOK();
1036
1037 // On Windows platforms, establish a default cache managment policy
1038 // as allowing OpenCPN a percentage of available physical memory,
1039 // not to exceed 1 GB
1040 // Note that this logic implies that Windows platforms always use
1041 // the memCacheLimit policy, and never use the fallback nCacheLimit policy
1042#ifdef __WXMSW__
1043 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1044 g_memCacheLimit =
1045 wxMin(g_memCacheLimit, 1024 * 1024); // math in kBytes, Max is 1 GB
1046#else
1047 // All other platforms will use the nCacheLimit policy
1048 // sinc on linux it is impossible to accurately measure the application memory
1049 // footprint without expensive methods such as malloc/free tracking, and such
1050
1051 g_memCacheLimit = 0;
1052 if (0 == g_nCacheLimit) // allow config file override
1053 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1054#endif
1055
1056 // Establish location and name of chart database
1057 ChartListFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(),
1058 "chartlist.dat", "CHRTLIST.DAT");
1059
1060 // Establish location and name of AIS MMSI -> Target Name mapping
1061 AISTargetNameFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(),
1062 "mmsitoname.csv", "MMSINAME.CSV");
1063
1064 // Establish guessed location of chart tree
1065 if (pInit_Chart_Dir->IsEmpty()) {
1066 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1067
1068 if (!g_bportable)
1069#ifndef __ANDROID__
1070 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1071#else
1072 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1073#endif
1074 }
1075
1076 InitRestListeners();
1077
1078 // Establish the GSHHS Dataset location
1079 gDefaultWorldMapLocation = "gshhs";
1080 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1081 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1082 if (gWorldMapLocation == wxEmptyString) {
1083 gWorldMapLocation = gDefaultWorldMapLocation;
1084 }
1085
1086 // Check the global Tide/Current data source array
1087 // If empty, preset default (US + ROW) data sources
1088 wxString default_tcdata0 =
1089 (g_Platform->GetSharedDataDir() + "tcdata" +
1090 wxFileName::GetPathSeparator() + "harmonics-dwf-20210110-free.tcd");
1091 wxString default_tcdata1 =
1092 (g_Platform->GetSharedDataDir() + "tcdata" +
1093 wxFileName::GetPathSeparator() + "HARMONICS_NO_US.IDX");
1094
1095 if (TideCurrentDataSet.empty()) {
1096 TideCurrentDataSet.push_back(
1097 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1098 TideCurrentDataSet.push_back(
1099 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1100 }
1101
1102 // Check the global AIS alarm sound file
1103 // If empty, preset default
1104 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1105 wxString default_sound = (g_Platform->GetSharedDataDir() + "sounds" +
1106 wxFileName::GetPathSeparator() + "2bells.wav");
1107 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1108 }
1109
1110 gpIDXn = 0;
1111
1112 g_Platform->Initialize_2();
1113
1114 // Set up the frame initial visual parameters
1115 // Default size, resized later
1116 wxSize new_frame_size(-1, -1);
1117 int cx, cy, cw, ch;
1118 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1119
1120 InitializeUserColors();
1121
1122 auto style = g_StyleManager->GetCurrentStyle();
1123 auto bitmap = new wxBitmap(style->GetIcon("default_pi", 32, 32));
1124 if (bitmap->IsOk())
1125 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1126 else
1127 wxLogWarning("Cannot initiate plugin default jigsaw icon.");
1128
1129 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1130 (g_nframewin_y <= ch))
1131 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1132 else
1133 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1134
1135 // Try to detect any change in physical screen configuration
1136 // This can happen when drivers are changed, for instance....
1137 // and can confuse the WUI layout perspective stored in the config file.
1138 // If detected, force a nominal window size and position....
1139 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1140 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1141 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1142 g_bframemax = false;
1143 }
1144
1145 g_lastClientRectx = cx;
1146 g_lastClientRecty = cy;
1147 g_lastClientRectw = cw;
1148 g_lastClientRecth = ch;
1149
1150 // Validate config file position
1151 wxPoint position(0, 0);
1152 wxSize dsize = wxGetDisplaySize();
1153
1154#ifdef __WXMAC__
1155 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1156#endif
1157
1158 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1159 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1160
1161#ifdef __WXMSW__
1162 // Support MultiMonitor setups which can allow negative window positions.
1163 RECT frame_rect;
1164 frame_rect.left = position.x;
1165 frame_rect.top = position.y;
1166 frame_rect.right = position.x + new_frame_size.x;
1167 frame_rect.bottom = position.y + new_frame_size.y;
1168
1169 // If the requested frame window does not intersect any installed monitor,
1170 // then default to simple primary monitor positioning.
1171 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1172 position = wxPoint(10, 10);
1173#endif
1174
1175#ifdef __WXOSX__
1176 // Support MultiMonitor setups which can allow negative window positions.
1177 const wxPoint ptScreen(position.x, position.y);
1178 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1179
1180 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1181#endif
1182
1183 g_nframewin_posx = position.x;
1184 g_nframewin_posy = position.y;
1185
1186#ifdef __ANDROID__
1187 wxSize asz = getAndroidDisplayDimensions();
1188 ch = asz.y;
1189 cw = asz.x;
1190 // qDebug() << cw << ch;
1191
1192 if ((cw > 200) && (ch > 200))
1193 new_frame_size.Set(cw, ch);
1194 else
1195 new_frame_size.Set(800, 400);
1196#endif
1197
1198 // For Windows and GTK, provide the expected application Minimize/Close bar
1199 long app_style = wxDEFAULT_FRAME_STYLE;
1200 app_style |= wxWANTS_CHARS;
1201
1202 // Create the main frame window
1203
1204 // Strip the commit SHA number from the string to be shown in frame title.
1205 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst('+');
1206 wxString myframe_window_title = wxString("OpenCPN " + short_version_name);
1207
1208 if (g_bportable) {
1209 myframe_window_title += _(" -- [Portable(-p) executing from ");
1210 myframe_window_title += g_Platform->GetHomeDir();
1211 myframe_window_title += "]";
1212 }
1213
1214 wxString fmsg;
1215 fmsg.Printf("Creating MyFrame...size(%d, %d) position(%d, %d)",
1216 new_frame_size.x, new_frame_size.y, position.x, position.y);
1217 wxLogMessage(fmsg);
1218
1220 auto dockart = new wxAuiDefaultDockArt;
1221 g_pauimgr->SetArtProvider(dockart);
1222
1223 gFrame = new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1224 app_style, dockart);
1225 wxTheApp->SetTopWindow(gFrame);
1226
1227 // Initialize the Plugin Manager
1228 g_pi_manager = new PlugInManager(gFrame);
1229
1230 // g_pauimgr = new wxAuiManager;
1231 g_pauimgr->SetDockSizeConstraint(.9, .9);
1232
1233 // g_pauimgr->SetFlags(g_pauimgr->GetFlags() | wxAUI_MGR_LIVE_RESIZE);
1234
1235 // tell wxAuiManager to manage the frame
1236 g_pauimgr->SetManagedWindow(gFrame);
1237
1238 // Do those platform specific initialization things that need gFrame
1239 g_Platform->Initialize_3();
1240
1241 gFrame->CreateCanvasLayout();
1242
1243 // gFrame->RequestNewMasterToolbar( true );
1244
1245 gFrame->SetChartUpdatePeriod(); // Reasonable default
1246
1247 gFrame->Enable();
1248
1249 gFrame->GetPrimaryCanvas()->SetFocus();
1250
1251 pthumbwin = new ThumbWin(gFrame->GetPrimaryCanvas());
1252
1253 gFrame->ApplyGlobalSettings(false); // done once on init with resize
1254
1255 gFrame->SetAllToolbarScale();
1256
1257 // Show the frame
1258 gFrame->Show(TRUE);
1259 Yield(); // required for Gnome 45
1260
1261 gFrame->SetAndApplyColorScheme(global_color_scheme);
1262
1263 if (g_bframemax) gFrame->Maximize(true);
1264
1265#ifdef __ANDROID__
1266 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->GetPixPerMM() > 4.0))
1267 gFrame->Maximize(true);
1268#endif
1269
1270 // Yield to pick up the OnSize() calls that result from Maximize()
1271 Yield();
1272
1273 // Build the initial chart dir array
1274 ArrayOfCDI ChartDirArray;
1275 pConfig->LoadChartDirArray(ChartDirArray);
1276
1277 // Windows installer may have left hints regarding the initial chart dir
1278 // selection
1279#ifdef __WXMSW__
1280 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1281 int ndirs = 0;
1282
1283 wxRegKey RegKey(wxString("HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1284 if (RegKey.Exists()) {
1285 wxLogMessage(
1286 _("Retrieving initial Chart Directory set from Windows Registry"));
1287 wxString dirs;
1288 RegKey.QueryValue(wxString("ChartDirs"), dirs);
1289
1290 wxStringTokenizer tkz(dirs, ";");
1291 while (tkz.HasMoreTokens()) {
1292 wxString token = tkz.GetNextToken();
1293
1294 ChartDirInfo cdi;
1295 cdi.fullpath = token.Trim();
1296 cdi.magic_number = "";
1297
1298 ChartDirArray.Add(cdi);
1299 ndirs++;
1300 }
1301 }
1302
1303 if (g_bportable) {
1304 ChartDirInfo cdi;
1305 cdi.fullpath = "charts";
1306 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1307 cdi.magic_number = "";
1308 ChartDirArray.Add(cdi);
1309 ndirs++;
1310 }
1311
1312 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1313 }
1314#endif
1315
1316 // If the ChartDirArray is empty at this point, any existing chart database
1317 // file must be declared invalid, So it is best to simply delete it if
1318 // present.
1319 // TODO There is a possibility of recreating the dir list from the
1320 // database itself......
1321
1322 if (!ChartDirArray.GetCount())
1323 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1324
1325 // Try to load the current chart list Data file
1326 ChartData = new ChartDB();
1327 if (g_NeedDBUpdate == 0 &&
1328 !ChartData->LoadBinary(ChartListFileName, ChartDirArray)) {
1329 g_NeedDBUpdate = 1;
1330 }
1331
1332 // Verify any saved chart database startup index
1333 if (g_restore_dbindex >= 0) {
1334 if (ChartData->GetChartTableEntries() == 0)
1335 g_restore_dbindex = -1;
1336
1337 else if (g_restore_dbindex > (ChartData->GetChartTableEntries() - 1))
1338 g_restore_dbindex = 0;
1339 }
1340
1341 // Apply the inital Group Array structure to the chart database
1342 ChartData->ApplyGroupArray(g_pGroupArray);
1343
1344 // All set to go.....
1345
1346 // Process command line option to rebuild cache
1347#ifdef ocpnUSE_GL
1348 extern ocpnGLOptions g_GLOptions;
1349
1350 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1351 g_GLOptions.m_bTextureCompressionCaching) {
1352 gFrame->ReloadAllVP(); // Get a nice chart background loaded
1353
1354 // Turn off the toolbar as a clear signal that the system is busy right
1355 // now.
1356 // Note: I commented this out because the toolbar never comes back for me
1357 // and is unusable until I restart opencpn without generating the cache
1358 // if( g_MainToolbar )
1359 // g_MainToolbar->Hide();
1360
1361 if (g_glTextureManager) g_glTextureManager->BuildCompressedCache();
1362 }
1363#endif
1364
1365 // FIXME (dave)
1366 // move method to frame
1367 // if (g_parse_all_enc) ParseAllENC(gFrame);
1368
1369 // establish GPS timeout value as multiple of frame timer
1370 // This will override any nonsense or unset value from the config file
1371 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1372 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1373
1374 wxString dogmsg;
1375 dogmsg.Printf("GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1376 wxLogMessage(dogmsg);
1377
1378 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1379
1380 g_priSats = 99;
1381
1382 // Most likely installations have no ownship heading information
1383 g_bVAR_Rx = false;
1384
1385 // Start up a new track if enabled in config file
1386 if (g_bTrackCarryOver) g_bDeferredStartTrack = true;
1387
1388 pAnchorWatchPoint1 = NULL;
1389 pAnchorWatchPoint2 = NULL;
1390
1391 Yield();
1392
1393 gFrame->DoChartUpdate();
1394
1395 FontMgr::Get()
1396 .ScrubList(); // Clean the font list, removing nonsensical entries
1397
1398 gFrame->ReloadAllVP(); // once more, and good to go
1399
1400 gFrame->Refresh(false);
1401 gFrame->Raise();
1402
1403 gFrame->GetPrimaryCanvas()->Enable();
1404 gFrame->GetPrimaryCanvas()->SetFocus();
1405
1406 // This little hack fixes a problem seen with some UniChrome OpenGL drivers
1407 // We need a deferred resize to get glDrawPixels() to work right.
1408 // So we set a trigger to generate a resize after 5 seconds....
1409 // See the "UniChrome" hack elsewhere
1410#ifdef ocpnUSE_GL
1411 if (!g_bdisable_opengl) {
1412 glChartCanvas *pgl =
1413 (glChartCanvas *)gFrame->GetPrimaryCanvas()->GetglCanvas();
1414 if (pgl && (pgl->GetRendererString().Find("UniChrome") != wxNOT_FOUND)) {
1415 gFrame->m_defer_size = gFrame->GetSize();
1416 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1417 g_pauimgr->Update();
1418 gFrame->m_bdefer_resize = true;
1419 }
1420 }
1421#endif
1422
1423 // Horrible Hack (tm): Make sure the RoutePoint destructor can invoke
1424 // glDeleteTextures. Truly awful.
1425#ifdef ocpnUSE_GL
1426 if (g_bopengl)
1427 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {
1428 glDeleteTextures(n, texts);
1429 };
1430#else
1431 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {};
1432#endif
1433
1434 if (g_start_fullscreen) gFrame->ToggleFullScreen();
1435
1436#ifdef __ANDROID__
1437 // We need a resize to pick up height adjustment after building android
1438 // ActionBar
1439 gFrame->SetSize(getAndroidDisplayDimensions());
1440 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1441#endif
1442
1443 gFrame->Raise();
1444 gFrame->GetPrimaryCanvas()->Enable();
1445 gFrame->GetPrimaryCanvas()->SetFocus();
1446
1447 // Setup Tides/Currents to settings present at last shutdown
1448 // TODO
1449 // gFrame->ShowTides( g_bShowTide );
1450 // gFrame->ShowCurrents( g_bShowCurrent );
1451
1452 // Start up the ticker....
1453 gFrame->FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
1454
1455 // Start up the ViewPort Rotation angle Averaging Timer....
1456 gFrame->FrameCOGTimer.Start(2000, wxTIMER_CONTINUOUS);
1457
1458 // Start up the Ten Hz timer....
1459 gFrame->FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
1460
1461 // wxLogMessage( wxString::Format("OpenCPN Initialized in %ld ms.",
1462 // init_sw.Time() ) );
1463
1464 OCPNPlatform::Initialize_4();
1465
1466#ifdef __ANDROID__
1467 androidHideBusyIcon();
1468#endif
1469 wxLogMessage(
1470 wxString::Format(_("OpenCPN Initialized in %ld ms."), init_sw.Time()));
1471
1472 wxMilliSleep(500);
1473
1474#ifdef __ANDROID__
1475 // We defer the startup message to here to allow the app frame to be
1476 // contructed, thus avoiding a dialog with NULL parent which might not work
1477 // on some devices.
1478 if (!n_NavMessageShown || (vs != g_config_version_string) ||
1479 (g_AndroidVersionCode != androidGetVersionCode())) {
1480 // qDebug() << "Showing NavWarning";
1481 wxMilliSleep(500);
1482
1483 if (!ShowNavWarning()) {
1484 qDebug() << "Closing due to NavWarning Cancel";
1485 gFrame->Close();
1486 androidTerminate();
1487 return true;
1488 }
1489
1490 n_NavMessageShown = 1;
1491 }
1492
1493 // Finished with upgrade checking, so persist the currect Version Code
1494 g_AndroidVersionCode = androidGetVersionCode();
1495 qDebug() << "Persisting Version Code: " << g_AndroidVersionCode;
1496#else
1497 // Send the Welcome/warning message if it has never been sent before,
1498 // or if the version string has changed at all
1499 // We defer until here to allow for localization of the message
1500 if (!n_NavMessageShown || (vs != g_config_version_string)) {
1501 if (!ShowNavWarning()) return false;
1502 n_NavMessageShown = 1;
1503 pConfig->Flush();
1504 }
1505#endif
1506
1507 // As an a.e. Raspberry does not have a hardwareclock we will have some
1508 // problems with date/time setting
1509 g_bHasHwClock = true; // by default most computers do have a hwClock
1510#if defined(__UNIX__) && !defined(__ANDROID__)
1511 struct stat buffer;
1512 g_bHasHwClock =
1513 ((stat("/dev/rtc", &buffer) == 0) || (stat("/dev/rtc0", &buffer) == 0) ||
1514 (stat("/dev/misc/rtc", &buffer) == 0));
1515#endif
1516
1517 g_config_version_string = vs;
1518
1519 // The user accepted the "not for navigation" nag, so persist it here...
1520 pConfig->UpdateSettings();
1521
1522 // Start delayed initialization chain after some milliseconds
1523 gFrame->InitTimer.Start(5, wxTIMER_CONTINUOUS);
1524
1525 g_pauimgr->Update();
1526
1527 for (auto *cp : TheConnectionParams()) {
1528 if (cp->bEnabled) {
1529 if (cp->GetDSPort().Contains("Serial")) {
1530 std::string port(cp->Port.ToStdString());
1531 CheckSerialAccess(gFrame, port);
1532 }
1533 }
1534 }
1535 CheckDongleAccess(gFrame);
1536
1537 // Initialize the CommBridge
1538 m_comm_bridge.Initialize();
1539
1540 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1541
1542 // If network connection is available, start the server and mDNS client
1543 if (ipv4_addrs.size()) {
1544 std::string ipAddr = ipv4_addrs[0];
1545
1546 wxString data_dir = g_Platform->GetPrivateDataDir();
1547 if (data_dir.Last() != wxFileName::GetPathSeparator())
1548 data_dir.Append(wxFileName::GetPathSeparator());
1549
1550 make_certificate(ipAddr, data_dir.ToStdString());
1551
1552 m_rest_server.StartServer(fs::path(data_dir.ToStdString()));
1553 StartMDNSService(g_hostname.ToStdString(), "opencpn-object-control-service",
1554 8000);
1555 }
1556 return TRUE;
1557}
1558
1559int MyApp::OnExit() {
1560 wxLogMessage("opencpn::MyApp starting exit.");
1561 m_checker.OnExit();
1562 m_usb_watcher.Stop();
1563 // Send current nav status data to log file // pjotrc 2010.02.09
1564
1565 wxDateTime lognow = wxDateTime::Now();
1566 lognow.MakeGMT();
1567 wxString day = lognow.FormatISODate();
1568 wxString utc = lognow.FormatISOTime();
1569 wxString navmsg = "LOGBOOK: ";
1570 navmsg += day;
1571 navmsg += " ";
1572 navmsg += utc;
1573 navmsg += " UTC ";
1574
1575 if (bGPSValid) {
1576 wxString data;
1577 data.Printf("OFF: Lat %10.5f Lon %10.5f ", gLat, gLon);
1578 navmsg += data;
1579
1580 wxString cog;
1581 if (std::isnan(gCog))
1582 cog.Printf("COG ----- ");
1583 else
1584 cog.Printf("COG %10.5f ", gCog);
1585
1586 wxString sog;
1587 if (std::isnan(gSog))
1588 sog.Printf("SOG ----- ");
1589 else
1590 sog.Printf("SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(gSog));
1591
1592 navmsg += cog;
1593 navmsg += sog;
1594
1595 } else {
1596 wxString data;
1597 data.Printf("OFF: Lat %10.5f Lon %10.5f", gLat, gLon);
1598 navmsg += data;
1599 }
1600 wxLogMessage(navmsg);
1601 g_loglast_time = lognow;
1602
1603 if (ptcmgr) delete ptcmgr;
1604
1605 for (Track *track : g_TrackList) {
1606 delete track;
1607 }
1608 g_TrackList.clear();
1609
1610 delete pConfig;
1611 delete pSelect;
1612 delete pSelectTC;
1613 delete pSelectAIS;
1614
1615 delete ps52plib;
1616 delete g_SencThreadManager;
1617
1618 if (g_pGroupArray) {
1619 for (unsigned int igroup = 0; igroup < g_pGroupArray->GetCount();
1620 igroup++) {
1621 delete g_pGroupArray->Item(igroup);
1622 }
1623
1624 g_pGroupArray->Clear();
1625 delete g_pGroupArray;
1626 }
1627
1628 wxLogMessage("opencpn::MyApp exiting cleanly...\n");
1629 wxLog::FlushActive();
1630
1631 g_Platform->CloseLogFile();
1632
1633 delete pInit_Chart_Dir;
1634
1635 for (Track *track : g_TrackList) {
1636 delete track;
1637 }
1638 g_TrackList.clear();
1639
1640 delete g_pRouteMan;
1641 delete pWayPointMan;
1642
1643 navutil::DeinitGlobals();
1644
1645 DeInitializeUserColors();
1646
1647 delete pLayerList;
1648
1649 delete m_pRegistrarMan;
1650 CSVDeaccess(NULL);
1651
1652 delete g_StyleManager;
1653
1654 // Restore any changed system colors
1655
1656#ifdef __WXMSW__
1657 void RestoreSystemColors();
1658 RestoreSystemColors();
1659#endif
1660
1661#ifdef __MSVC__LEAK
1662 DeInitAllocCheck();
1663#endif
1664
1665#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1666 if (plocale_def_lang) delete plocale_def_lang;
1667#endif
1668
1669 FontMgr::Shutdown();
1670
1671 g_Platform->OnExit_2();
1673 delete g_Platform;
1674
1675 return TRUE;
1676}
1677
1678#ifdef LINUX_CRASHRPT
1679void MyApp::OnFatalException() { g_crashprint.Report(); }
1680#endif
1681
1682//----------------------------------------------------------------------------------------------------------
1683// Application-wide CPL Error handler
1684//----------------------------------------------------------------------------------------------------------
1685void MyCPLErrorHandler(CPLErr eErrClass, int nError, const char *pszErrorMsg)
1686
1687{
1688 char msg[256];
1689
1690 if (eErrClass == CE_Debug)
1691 snprintf(msg, 255, "CPL: %s", pszErrorMsg);
1692 else if (eErrClass == CE_Warning)
1693 snprintf(msg, 255, "CPL Warning %d: %s", nError, pszErrorMsg);
1694 else
1695 snprintf(msg, 255, "CPL ERROR %d: %s", nError, pszErrorMsg);
1696
1697 wxString str(msg, wxConvUTF8);
1698 wxLogMessage(str);
1699}
class About
Class AboutFrameImpl.
Select * pSelectAIS
Global instance.
wxString AISTargetNameFileName
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetListDialog.
Class AISTargetQueryDialog.
BasePlatform * g_BasePlatform
points to g_platform, handles brain-dead MS linker.
bool GetMemoryStatus(int *mem_total, int *mem_used)
Return total system RAM and size of program Values returned are in kilobytes.
Chart canvas configuration state
Purpose: TLS Certificate support.
ChartDB * ChartData
Global instance.
Definition chartdb.cpp:70
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Definition chartdbs.cpp:56
Generic Chart canvas base.
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
EventVar reverse_route
Notified with a string GUID when user wants to reverse a route.
EventVar activate_route
Notified with a string GUID when user wants to activate a route.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
Definition chcanv.h:515
Manages the chart database and provides access to chart data.
Definition chartdb.h:95
bool LoadBinary(const wxString &filename, ArrayOfCDI &dir_array_check)
Load the chart database from a binary file.
Definition chartdb.cpp:229
void Notify() override
Notify all listeners, no data supplied.
void ScrubList()
Cleans up stale font entries after a locale change.
Definition font_mgr.cpp:555
static void SeedRandom()
Seed the random generator used by GetUUID().
Common interface for all instance checkers.
virtual bool IsMainInstance()=0
Return true if this process is the primary opencpn instance.
virtual void CleanUp()
Remove all persistent instance state, including possible lock file and defunct opencpn processes.
virtual void OnExit()
Do whatever needed before wxWidget's checks triggers.
virtual void WaitUntilValid()
Wait until this object can be used for example for Dbus connection.
static LocalServerApi & GetInstance()
Main application frame.
Definition ocpn_frame.h:139
Provides platform-specific support utilities for OpenCPN.
void SetDisplaySizeMM(size_t monitor, double size)
Set the width of the monitor in millimeters.
double GetDisplaySizeMM()
Get the width of the screen in millimeters.
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
Definition observable.h:295
bool LoadAllPlugIns(bool enabled_plugins, bool keep_orphans=false)
Update catalog with imported metadata and load all plugin library files.
bool StartServer(const fs::path &certificate_location) override
Start the server thread.
Represents a waypoint or mark within the navigation system.
Definition route_point.h:71
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Definition route_point.h:47
Represents a navigational route in the navigation system.
Definition route.h:99
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
Definition route.h:203
wxString m_RouteNameString
User-assigned name for the route.
Definition route.h:247
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
Definition routeman.h:265
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Definition routeman.cpp:222
Window for displaying chart thumbnails.
Definition thumbwin.h:47
Represents a track, which is a series of connected track points.
Definition track.h:117
Listen to hardware events and notifies SystemEvents when new devices are plugged in.
OpenGL chart rendering canvas.
Handles crash reporting in wxWidgets applications.
Definition crashprint.h:24
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
CommBridge class and helpers.
NMEA Data Multiplexer Object.
Variables maintained by comm stack, read-only access for others.
Primary navigation console display for route and vessel tracking.
Config file user configuration interface.
std::vector< size_t > g_config_display_size_mm
Size of pysical screen in millimeters.
double g_display_size_mm
Physical display width (mm)
Global variables stored in configuration file.
Dump debug info on crash.
Chart display details slider.
Font list manager.
NMEA Data Object.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture cache.
Go to position dialog...
size_t g_current_monitor
Current monitor displaying main application frame.
Definition gui_vars.cpp:75
int g_NeedDBUpdate
0 - No update needed, 1 - Update needed because there is no chart database, inform user 2 - Start upd...
Definition gui_vars.cpp:94
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Instance check interface.
Chart object layer.
The local API has a server side handling commands and a client part issuing commands.
Enhanced logging interface on top of wx/log.h.
MacOS hardware probing functions.
Waypoint properties maintenance dialog.
mDNS lookup wrappers.
Start/stop mdns service routines.
Multiplexer class and helpers.
void check_last_start()
Check if the last start failed, possibly invoke user dialog and set safe mode state.
void clear_check()
Mark last run as successful.
Definition safe_mode.cpp:62
MySQL based storage for routes, tracks, etc.
Utility functions.
Navigation Utility Functions without GUI dependencies.
User notifications manager.
s57RegistrarMgr * m_pRegistrarMan
Global instance.
Definition o_senc.cpp:62
S57 SENC File Object.
General observable implementation with several specializations.
OpenCPN main program.
OCPN_AUIManager * g_pauimgr
Global instance.
OCPN_AUIManager.
OpenCPN top window.
OpenCPN Platform specific support utilities.
Options dialog.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
Definition own_ship.cpp:34
double gLat
Vessel's current latitude in decimal degrees.
Definition own_ship.cpp:26
double gCog
Course over ground in degrees (0-359.99).
Definition own_ship.cpp:28
double gSog
Speed over ground in knots.
Definition own_ship.cpp:29
double gLon
Vessel's current longitude in decimal degrees.
Definition own_ship.cpp:27
Position, course, speed, etc.
Plugin remote repositories installation and Uninstall/list operations.
PlugInManager * g_pi_manager
Global instance.
REST server dialogs.
Route abstraction.
Route properties dialog.
RoutePoint * pAnchorWatchPoint2
Global instance.
Definition routeman.cpp:64
Routeman * g_pRouteMan
Global instance.
Definition routeman.cpp:60
RouteList * pRouteList
Global instance.
Definition routeman.cpp:66
RoutePoint * pAnchorWatchPoint1
Global instance.
Definition routeman.cpp:63
Route Manager.
Routeman drawing stuff.
Manage routes dialog.
S57 object query result window.
S57 Chart Object.
Select * pSelect
Global instance.
Definition select.cpp:36
Select * pSelectTC
Global instance.
Definition select.cpp:37
Selected route, segment, waypoint, etc.
SENCThreadManager * g_SencThreadManager
Global instance.
Chart Symbols.
TCMgr * ptcmgr
Global instance.
Definition tcmgr.cpp:42
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
Definition thumbwin.cpp:40
Chart thumbnail object.
std::vector< Track * > g_TrackList
Global instance.
Definition track.cpp:96
Recorded track abstraction.
Track Properties Dialog.
bool CheckDongleAccess(wxWindow *parent)
Runs checks and if required dialogs to make dongle accessible.
bool CheckSerialAccess(wxWindow *parent, const std::string device)
Run checks and possible dialogs to ensure device is accessible.
Access checks for comm devices and dongle.