51#include <wx/msw/msvcrt.h>
63#if defined(__WXMSW__) && defined(__MSVC__LEAK)
64#include "Stackwalker.h"
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>
83#include <wx/display.h>
88#include <wx/jsonreader.h>
89#include <wx/listctrl.h>
91#include <wx/printdlg.h>
93#include <wx/progdlg.h>
94#include <wx/settings.h>
95#include <wx/stdpaths.h>
96#include <wx/tokenzr.h>
98#include "o_sound/o_sound.h"
116#include "model/nav_object_database.h"
128#include "ais_info_gui.h"
142#include "gdal/cpl_csv.h"
156#include "route_ctx_factory.h"
163#include "safe_mode_gui.h"
164#include "std_filesystem.h"
182void RedirectIOToConsole();
194#include "androidUTIL.h"
199using namespace std::literals::chrono_literals;
201const char *
const kUsage =
204 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
205 opencpn --remote [-R] | -q] | -e] |-o <str>]
207Options for starting opencpn
209 -c, --configdir=<dirpath> Use alternative configuration directory.
210 -p, --portable Run in portable mode.
211 -f, --fullscreen Switch to full screen mode on start.
212 -G, --no_opengl Disable OpenGL video acceleration. This setting will
214 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
215 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
216 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
217 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
218 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
219 Zero or negative <num> specifies no limit.
221 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
222 -W, --config_wizard Start with initial configuration wizard
224Options manipulating already started opencpn
225 -r, --remote Execute commands on already running instance
226 -R, --raise Make running OpenCPN visible if hidden
227 -q, --quit Terminate already running opencpn
228 -e, --get_rest_endpoint Print rest server endpoint and exit.
229 -o, --open=<GPX file> Open file in running opencpn
232 GPX file GPX-formatted file with waypoints or routes.
236wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
237wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
239wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
240wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
241wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
242wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
243wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
244wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
245wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
246wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
247wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
257WX_DEFINE_OBJARRAY(ArrayOfCDI);
259static int user_user_id;
260static int file_user_id;
262static int g_mem_total, g_mem_initial;
264static unsigned int malloc_max;
266static int osMajor, osMinor;
268static bool g_bHasHwClock;
270#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
272wxLocale *plocale_def_lang = 0;
280extern sigjmp_buf env;
285DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
286 0x6b, 0xba, 0xe7, 0x22, 0xc0);
290static const long long lNaN = 0xfff8000000000000;
291#define NAN (*(double *)&lNaN)
295void appendOSDirSlash(wxString *pString);
297void InitializeUserColors();
298void DeInitializeUserColors();
299void SetSystemColors(ColorScheme cs);
301static bool LoadAllPlugIns(
bool load_enabled) {
302 g_Platform->ShowBusySpinner();
303 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
304 g_Platform->HideBusySpinner();
312#if defined(__WXGTK__) || defined(__WXQT__)
313#include "bitmaps/opencpn.xpm"
316wxString newPrivateFileName(wxString,
const char *name,
317 [[maybe_unused]]
const char *windowsName) {
318 wxString fname = wxString::FromUTF8(name);
319 wxString filePathAndName;
322 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
323 filePathAndName.Append(wxFileName::GetPathSeparator());
326 wxString fwname = wxString::FromUTF8(windowsName);
327 filePathAndName.Append(fwname);
329 filePathAndName.Append(fname);
332 return filePathAndName;
338 : wxFrame(
nullptr, wxID_ANY,
"Loading...", wxDefaultPosition,
339 wxSize(900, 600), wxSTAY_ON_TOP) {
341 SetBackgroundColour(wxColour(0, 0, 0));
345 new wxStaticText(
this, wxID_ANY,
"", wxDefaultPosition, wxDefaultSize,
346 wxALIGN_CENTRE_HORIZONTAL);
347 text->SetForegroundColour(wxColour(255, 255, 255));
349 wxBoxSizer *sizer =
new wxBoxSizer(wxVERTICAL);
350 sizer->Add(text, 1, wxALIGN_CENTER);
351 SetSizerAndFit(sizer);
363BEGIN_EVENT_TABLE(
MyApp, wxApp)
364EVT_ACTIVATE_APP(MyApp::OnActivateApp)
367static
void ActivateRoute(const std::
string &guid) {
370 wxLogMessage(
"Cannot activate guid: no such route");
381 point = route->GetPoint(2);
388static void ReverseRoute(
const std::string &guid) {
391 wxLogMessage(
"Cannot activate guid: no such route");
398void MyApp::InitRestListeners() {
399 auto activate_route = [&](wxCommandEvent ev) {
400 auto guid = ev.GetString().ToStdString();
404 auto reverse_route = [&](wxCommandEvent ev) {
405 auto guid = ev.GetString().ToStdString();
411bool MyApp::OpenFile(
const std::string &path) {
413 auto result = nav_objects.load_file(path.c_str());
415 std::string s(_(
"Cannot load route or waypoint file: "));
416 s += std::string(
"\"") + path +
"\"";
417 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
423 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
425 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
426 pRouteManagerDialog->UpdateLists();
427 LLBBox box = nav_objects.GetBBox();
428 if (box.GetValid()) {
429 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
435void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
438 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
439 parser.AddSwitch(
"p",
"portable");
440 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
441 wxCMD_LINE_PARAM_OPTIONAL);
442 parser.AddSwitch(
"f",
"fullscreen");
443 parser.AddSwitch(
"G",
"no_opengl");
444 parser.AddSwitch(
"W",
"config_wizard");
445 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
446 parser.AddSwitch(
"D",
"rebuild_chart_db");
447 parser.AddSwitch(
"P",
"parse_all_enc");
448 parser.AddOption(
"l",
"loglevel");
449 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
450 parser.AddSwitch(
"U",
"unit_test_2");
451 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
452 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
453 parser.AddSwitch(
"s",
"safe_mode");
454 parser.AddSwitch(
"r",
"remote");
455 parser.AddSwitch(
"R",
"raise");
456 parser.AddSwitch(
"q",
"quit");
457 parser.AddSwitch(
"e",
"get_rest_endpoint");
458 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
459 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
465static void ParseLoglevel(wxCmdLineParser &parser) {
466 wxLog::SetLogLevel(wxLOG_Message);
469static void ParseLoglevel(wxCmdLineParser &parser) {
470 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
471 strLevel = strLevel ? strLevel :
"info";
473 if (parser.Found(
"l", &wxLevel)) {
474 strLevel = wxLevel.c_str();
476 wxLogLevel level = OcpnLog::str2level(strLevel);
477 if (level == OcpnLog::LOG_BADLEVEL) {
478 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
481 wxLog::SetLogLevel(level);
486bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
493bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
498 g_unit_test_2 = parser.Found(
"unit_test_2");
499 g_bportable = parser.Found(
"p");
500 g_start_fullscreen = parser.Found(
"fullscreen");
501 g_bdisable_opengl = parser.Found(
"no_opengl");
502 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
504 g_parse_all_enc = parser.Found(
"parse_all_enc");
505 g_config_wizard = parser.Found(
"config_wizard");
506 if (parser.Found(
"unit_test_1", &number)) {
507 g_unit_test_1 =
static_cast<int>(number);
508 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
510 safe_mode::set_mode(parser.Found(
"safe_mode"));
511 ParseLoglevel(parser);
513 if (parser.Found(
"configdir", &wxstr)) {
514 g_configdir = wxstr.ToStdString();
515 fs::path path(g_configdir);
516 if (!fs::exists(path) || !fs::is_directory(path)) {
517 std::cerr << g_configdir <<
" is not an existing directory.\n";
522 bool has_start_options =
false;
523 static const std::vector<std::string> kStartOptions = {
528 "rebuild_gl_raster_cache",
534 for (
const auto &opt : kStartOptions) {
535 if (parser.Found(opt)) has_start_options =
true;
537 if (has_start_options && parser.Found(
"remote")) {
538 std::cerr <<
"this option is not compatible with --remote\n";
542 bool has_remote_options =
false;
543 static const std::vector<std::string> kRemoteOptions = {
544 "raise",
"quit",
"open",
"get_rest_endpoint"};
545 for (
const auto &opt : kRemoteOptions) {
546 if (parser.Found(opt)) has_remote_options =
true;
548 if (has_remote_options && !parser.Found(
"remote")) {
549 std::cerr <<
"This option requires --remote\n";
553 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
554 g_params.push_back(parser.GetParam(paramNr).ToStdString());
557 if (!parser.Found(
"remote"))
558 m_parsed_cmdline = ParsedCmdline();
559 else if (parser.Found(
"raise"))
560 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
561 else if (parser.Found(
"quit"))
562 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
563 else if (parser.Found(
"get_rest_endpoint"))
564 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
565 else if (parser.Found(
"open", &optarg))
566 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
567 else if (parser.GetParamCount() == 1)
569 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
570 else if (!has_start_options && !has_remote_options) {
572 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
582bool MyApp::OnExceptionInMainLoop() {
583 wxLogWarning(
"Caught MainLoopException, continuing...");
588void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
590static wxStopWatch init_sw;
593 if (m_exitcode != -2)
return m_exitcode;
594 return wxAppConsole::OnRun();
605 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
606 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
607 setenv(
"GDK_BACKEND",
"x11", 1);
611 "mesa_glthread",
"false",
620 if (!wxApp::OnInit())
return false;
623 androidEnableBackButton(
false);
624 androidEnableOptionItems(
false);
629#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
635 wxBitmap bmp(10, 10, -1);
637 dc.SelectObject(bmp);
638 dc.DrawText(
"X", 0, 0);
650 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
654 std::cerr <<
"No remote opencpn found. Giving up.\n";
659 std::unique_ptr<LocalClientApi> client;
661 client = LocalClientApi::GetClient();
663 WARNING_LOG <<
"Ipc client exception: " << ie.str();
670 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
671 "to respond.\nPlease retry."),
672 "OpenCPN", wxICON_INFORMATION | wxOK);
677 auto result = client->HandleCmdline(m_parsed_cmdline.action,
678 m_parsed_cmdline.arg);
682 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
691 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
692 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
697 if (!safe_mode::get_mode()) {
703 OCPNPlatform::Initialize_1();
708 MyApp::SetAppDisplayName(
"OpenCPN");
711 wxDateTime x = wxDateTime::UNow();
712 long seed = x.GetMillisecond();
713 seed *= x.GetTicks();
718 setlocale(LC_NUMERIC,
"C");
720 g_start_time = wxDateTime::Now();
722 g_loglast_time = g_start_time;
723 g_loglast_time.MakeGMT();
724 g_loglast_time.Subtract(
725 wxTimeSpan(0, 29, 0, 0));
727 AnchorPointMinDist = 5.0;
733 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
737 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
738 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
739 wxFONTENCODING_SYSTEM);
740 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
743 auto ¬eman = NotificationManager::GetInstance();
744 noteman.ScrubNotificationDirectory(30);
747 if (!g_Platform->InitializeLogFile()) {
759 wxLogMessage(
"\n\n________\n");
761 wxDateTime now = wxDateTime::Now();
762 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
763 now.FormatISODate().mb_str().data());
764 wxLogLevel level = wxLog::GetLogLevel();
765 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
767 wxString wxver(wxVERSION_STRING);
768 wxver.Prepend(
"wxWidgets version: ");
770 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
774 os_name = platforminfo.GetOperatingSystemIdName();
776 os_name = platforminfo.GetOperatingSystemFamilyName();
779 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
780 platforminfo.GetPortIdName();
782 wxLogMessage(wxver +
" " + platform);
784 ::wxGetOsVersion(&osMajor, &osMinor);
785 wxString osVersionMsg;
786 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
787 wxLogMessage(osVersionMsg);
789 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
790 g_mem_total / 1024, g_mem_initial / 1024);
795 if (!detail->osd_names_like.empty())
796 like0 = detail->osd_names_like[0].c_str();
797 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
798 detail->osd_arch.c_str(), detail->osd_name.c_str(),
799 detail->osd_version.c_str(), detail->osd_ID.c_str(),
801 wxLogMessage(msgplat);
803 wxString imsg =
"SData_Locn is ";
804 imsg += g_Platform->GetSharedDataDir();
808 ::wxInitAllImageHandlers();
812 prepareAndroidStyleSheets();
816 pInit_Chart_Dir =
new wxString();
821 imsg =
"PrivateDataDir is ";
827 navutil::InitGlobals();
831 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
835 pSelect->SetSelectPixelRadius(12);
848 g_pais_query_dialog_active = NULL;
851 g_hostname = ::wxGetHostName();
852 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
854 androidGetDeviceInfo();
855 g_hostname = wxString(
"Android-") + g_android_Device_Model;
856 g_hostname.Replace(
" ",
"-",
true);
861 wxString p(
"Portable-");
862 g_hostname = p + g_hostname;
867 pLayerList =
new LayerList;
872 auto &navobj_db = NavObj_dB::GetInstance();
879#ifdef PROBE_PORTS__WITH_HELPER
880 user_user_id = getuid();
881 file_user_id = geteuid();
885 bool b_initial_load =
false;
887 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
888 if (config_test_file_name.FileExists())
889 wxLogMessage(
"Using existing Config_File: " +
890 g_Platform->GetConfigFileName());
893 wxLogMessage(
"Creating new Config_File: " +
894 g_Platform->GetConfigFileName());
896 b_initial_load =
true;
899 config_test_file_name.DirExists(config_test_file_name.GetPath()))
900 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
901 wxLogMessage(
"Cannot create config file directory for " +
902 g_Platform->GetConfigFileName());
907 pConfig = g_Platform->GetConfigObject();
908 InitBaseConfig(pConfig);
909 pConfig->LoadMyConfig();
911 if (g_kiosk_startup) {
913 g_wallpaper->ShowFullScreen(
true);
919 if (b_initial_load) g_Platform->SetDefaultOptions();
921 g_Platform->applyExpertMode(g_bUIexpert);
926 g_StyleManager->SetStyle(
"MUI_flat");
927 if (!g_StyleManager->IsOK()) {
928 wxString msg = _(
"Failed to initialize the user interface. ");
929 msg << _(
"OpenCPN cannot start. ");
930 msg << _(
"The necessary configuration files were not found. ");
931 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
932 << _(
" for details.") <<
"\n\n";
933 msg << g_Platform->GetSharedDataDir();
935 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
936 wxCANCEL | wxICON_ERROR);
943 if (style) style->chartStatusWindowTransparent =
true;
951 msg.Printf(
"Detected display size (horizontal): %d mm",
956 if (g_config_display_size_manual &&
961 msg.Printf(
"Display size (horizontal) config override: %d mm",
970 int SelectPixelRadius = 50;
972 pSelect->SetSelectPixelRadius(SelectPixelRadius);
973 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
974 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
978 if (!n_NavMessageShown) {
985#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
988 g_Platform->SetLocaleSearchPrefixes();
990 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
992 imsg =
"System default Language: " + def_lang_canonical;
995 wxString cflmsg =
"Config file language: " + g_locale;
996 wxLogMessage(cflmsg);
998 if (g_locale.IsEmpty()) {
999 g_locale = def_lang_canonical;
1000 cflmsg =
"Config file language empty, using system default: " + g_locale;
1001 wxLogMessage(cflmsg);
1005 g_locale = g_Platform->GetAdjustedAppLocale();
1006 cflmsg =
"Adjusted App language: " + g_locale;
1007 wxLogMessage(cflmsg);
1010 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1012 imsg =
"Opencpn language set to: ";
1019 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1021 wxLogMessage(
"wxLocale support not available");
1026 if (g_config_wizard || b_initial_load) {
1028 auto res = wiz.Run();
1039 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1040 g_bUpgradeInProcess = (vs != g_config_version_string);
1042 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1045 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1046 wxLogMessage(g_Platform->GetLargeLogMessage());
1051 g_bdisable_opengl =
true;
1054 if (g_bdisable_opengl) g_bopengl =
false;
1056#if defined(__linux__) && !defined(__ANDROID__)
1057 if (g_bSoftwareGL) {
1058 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1071 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1073 wxMin(g_memCacheLimit, 1024 * 1024);
1079 g_memCacheLimit = 0;
1080 if (0 == g_nCacheLimit)
1081 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1086 "chartlist.dat",
"CHRTLIST.DAT");
1090 "mmsitoname.csv",
"MMSINAME.CSV");
1093 if (pInit_Chart_Dir->IsEmpty()) {
1094 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1098 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1100 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1104 InitRestListeners();
1107 gDefaultWorldMapLocation =
"gshhs";
1108 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1109 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1110 if (gWorldMapLocation == wxEmptyString) {
1111 gWorldMapLocation = gDefaultWorldMapLocation;
1116 wxString default_tcdata0 =
1117 (g_Platform->GetSharedDataDir() +
"tcdata" +
1118 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1119 wxString default_tcdata1 =
1120 (g_Platform->GetSharedDataDir() +
"tcdata" +
1121 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1123 if (TideCurrentDataSet.empty()) {
1124 TideCurrentDataSet.push_back(
1125 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1126 TideCurrentDataSet.push_back(
1127 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1132 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1133 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1134 wxFileName::GetPathSeparator() +
"2bells.wav");
1135 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1140 g_Platform->Initialize_2();
1142 LoadChartDatabase();
1146 g_kiosk_startup =
false;
1150 if (!g_kiosk_startup) {
1152 SetTopWindow(gFrame);
1157 gFrame->InitTimer.Start(50, wxTIMER_CONTINUOUS);
1163 OCPNPlatform::Initialize_4();
1166 androidHideBusyIcon();
1169 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1177 if (!n_NavMessageShown || (vs != g_config_version_string) ||
1178 (g_AndroidVersionCode != androidGetVersionCode())) {
1182 if (!ShowNavWarning()) {
1183 qDebug() <<
"Closing due to NavWarning Cancel";
1189 n_NavMessageShown = 1;
1193 g_AndroidVersionCode = androidGetVersionCode();
1194 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
1199 if (!n_NavMessageShown || (vs != g_config_version_string)) {
1200 if (!ShowNavWarning())
return false;
1201 n_NavMessageShown = 1;
1208 g_bHasHwClock =
true;
1209#if defined(__UNIX__) && !defined(__ANDROID__)
1212 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1213 (stat(
"/dev/misc/rtc", &buffer) == 0));
1216 g_config_version_string = vs;
1219 pConfig->UpdateSettings();
1221 for (
auto *cp : TheConnectionParams()) {
1223 if (cp->GetDSPort().Contains(
"Serial")) {
1224 std::string port(cp->Port.ToStdString());
1232 m_comm_bridge.Initialize();
1234 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1237 if (ipv4_addrs.size()) {
1238 std::string ipAddr = ipv4_addrs[0];
1241 if (data_dir.Last() != wxFileName::GetPathSeparator())
1242 data_dir.Append(wxFileName::GetPathSeparator());
1244 make_certificate(ipAddr, data_dir.ToStdString());
1246 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1247 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1258 g_wallpaper->Show(
false);
1261 gFrame->ShowFullScreen(
true);
1264 g_wallpaper->Destroy();
1265 g_wallpaper =
nullptr;
1267 SetTopWindow(gFrame);
1271 gFrame->InitTimer.Start(50, wxTIMER_CONTINUOUS);
1277 wxSize new_frame_size(-1, -1);
1279 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1281 InitializeUserColors();
1283 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1284 (g_nframewin_y <= ch))
1285 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1287 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1293 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1294 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1295 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1296 g_bframemax =
false;
1299 g_lastClientRectx = cx;
1300 g_lastClientRecty = cy;
1301 g_lastClientRectw = cw;
1302 g_lastClientRecth = ch;
1305 wxPoint position(0, 0);
1306 wxSize dsize = wxGetDisplaySize();
1309 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1312 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1313 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1318 frame_rect.left = position.x;
1319 frame_rect.top = position.y;
1320 frame_rect.right = position.x + new_frame_size.x;
1321 frame_rect.bottom = position.y + new_frame_size.y;
1325 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1326 position = wxPoint(10, 10);
1331 const wxPoint ptScreen(position.x, position.y);
1332 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1334 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1337 g_nframewin_posx = position.x;
1338 g_nframewin_posy = position.y;
1341 wxSize asz = getAndroidDisplayDimensions();
1346 if ((cw > 200) && (ch > 200))
1347 new_frame_size.Set(cw, ch);
1349 new_frame_size.Set(800, 400);
1353 long app_style = wxDEFAULT_FRAME_STYLE;
1354 app_style |= wxWANTS_CHARS;
1359 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1360 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1363 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1364 myframe_window_title += g_Platform->GetHomeDir();
1365 myframe_window_title +=
"]";
1369 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1370 new_frame_size.x, new_frame_size.y, position.x, position.y);
1374 auto dockart =
new wxAuiDefaultDockArt;
1377 gFrame =
new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1378 app_style, dockart);
1383 g_pauimgr->SetDockSizeConstraint(.9, .9);
1389 g_Platform->Initialize_3();
1391 gFrame->CreateCanvasLayout();
1395 gFrame->SetChartUpdatePeriod();
1399 gFrame->ApplyGlobalSettings(
false);
1400 gFrame->SetAllToolbarScale();
1401 gFrame->SetAndApplyColorScheme(global_color_scheme);
1402 if (g_bframemax) gFrame->Maximize(
true);
1405 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->
GetPixPerMM() > 4.0))
1406 gFrame->Maximize(
true);
1415 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1416 g_GLOptions.m_bTextureCompressionCaching) {
1417 gFrame->ReloadAllVP();
1436 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1437 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1440 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1441 wxLogMessage(dogmsg);
1443 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1451 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1456 gFrame->DoChartUpdate();
1459 auto style = g_StyleManager->GetCurrentStyle();
1460 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1462 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1464 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1474 wxString perspective;
1475 pConfig->SetPath(
"/AUI");
1476 pConfig->Read(
"AUIPerspective", &perspective);
1483 bool bno_load =
false;
1485 wxArrayString name_array;
1486 wxStringTokenizer st(perspective,
"|;");
1487 while (st.HasMoreTokens()) {
1488 wxString s1 = st.GetNextToken();
1489 if (s1.StartsWith(
"name=")) {
1490 wxString sc = s1.AfterFirst(
'=');
1495 wxAuiPaneInfoArray pane_array_val =
g_pauimgr->GetAllPanes();
1496 for (
unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1497 wxAuiPaneInfo pane = pane_array_val.Item(i);
1501 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1507 if (!bno_load)
g_pauimgr->LoadPerspective(perspective,
false);
1512 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1515 wxSize frameSize = GetClientSize();
1516 wxSize minSize =
g_pauimgr->GetPane(cc).min_size;
1517 int width = wxMax(minSize.x, frameSize.x / 10);
1518 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1535 gFrame->DoChartUpdate();
1540 gFrame->ReloadAllVP();
1542 gFrame->Refresh(
false);
1545 gFrame->GetPrimaryCanvas()->Enable();
1546 gFrame->GetPrimaryCanvas()->SetFocus();
1553 if (!g_bdisable_opengl) {
1556 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1557 gFrame->m_defer_size = gFrame->GetSize();
1558 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1560 gFrame->m_bdefer_resize =
true;
1570 glDeleteTextures(n, texts);
1576 if (g_start_fullscreen) gFrame->ToggleFullScreen();
1581 gFrame->SetSize(getAndroidDisplayDimensions());
1582 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0,
true);
1586 gFrame->GetPrimaryCanvas()->Enable();
1587 gFrame->GetPrimaryCanvas()->SetFocus();
1598void MyApp::LoadChartDatabase() {
1600 ArrayOfCDI ChartDirArray;
1601 pConfig->LoadChartDirArray(ChartDirArray);
1606 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1609 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1610 if (RegKey.Exists()) {
1612 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1614 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1616 wxStringTokenizer tkz(dirs,
";");
1617 while (tkz.HasMoreTokens()) {
1618 wxString token = tkz.GetNextToken();
1621 cdi.fullpath = token.Trim();
1622 cdi.magic_number =
"";
1624 ChartDirArray.Add(cdi);
1631 cdi.fullpath =
"charts";
1632 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1633 cdi.magic_number =
"";
1634 ChartDirArray.Add(cdi);
1638 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1648 if (!ChartDirArray.GetCount())
1649 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1659 if (g_restore_dbindex >= 0) {
1660 if (
ChartData->GetChartTableEntries() == 0)
1661 g_restore_dbindex = -1;
1663 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1664 g_restore_dbindex = 0;
1672 wxLogMessage(
"opencpn::MyApp starting exit.");
1674 m_usb_watcher.Stop();
1677 wxDateTime lognow = wxDateTime::Now();
1679 wxString day = lognow.FormatISODate();
1680 wxString utc = lognow.FormatISOTime();
1681 wxString navmsg =
"LOGBOOK: ";
1689 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ",
gLat,
gLon);
1693 if (std::isnan(
gCog))
1694 cog.Printf(
"COG ----- ");
1696 cog.Printf(
"COG %10.5f ",
gCog);
1699 if (std::isnan(
gSog))
1700 sog.Printf(
"SOG ----- ");
1702 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(
gSog));
1709 data.Printf(
"OFF: Lat %10.5f Lon %10.5f",
gLat,
gLon);
1712 wxLogMessage(navmsg);
1713 g_loglast_time = lognow;
1731 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1740 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1741 wxLog::FlushActive();
1743 g_Platform->CloseLogFile();
1745 delete pInit_Chart_Dir;
1753 delete pWayPointMan;
1755 navutil::DeinitGlobals();
1757 DeInitializeUserColors();
1764 delete g_StyleManager;
1769 void RestoreSystemColors();
1770 RestoreSystemColors();
1777#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1781 FontMgr::Shutdown();
1783 g_Platform->OnExit_2();
1790#ifdef LINUX_CRASHRPT
1791void MyApp::OnFatalException() { g_crashprint.Report(); }
1797void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1802 if (eErrClass == CE_Debug)
1803 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1804 else if (eErrClass == CE_Warning)
1805 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1807 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1809 wxString str(msg, wxConvUTF8);
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.
Chart canvas configuration state
Purpose: TLS Certificate support.
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Generic Chart canvas base.
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.
ChartCanvas - Main chart display and interaction component.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
Manages the chart database and provides access to chart data.
bool LoadBinary(const wxString &filename, ArrayOfCDI &dir_array_check)
Load the chart database from a binary file.
void Notify() override
Notify all listeners, no data supplied.
void ScrubList()
Cleans up stale font entries after a locale change.
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()
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
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.
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
wxString m_RouteNameString
User-assigned name for the route.
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Window for displaying chart thumbnails.
Represents a track, which is a series of connected track points.
Listen to hardware events and notifies SystemEvents when new devices are plugged in.
OpenGL chart rendering canvas.
Handles crash reporting in wxWidgets applications.
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.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
size_t g_current_monitor
Current monitor displaying main application frame.
int g_NeedDBUpdate
0 - No update needed, 1 - Update needed because there is no chart database, inform user 2 - Start upd...
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Instance check interface.
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.
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.
MySQL based storage for routes, tracks, etc.
Navigation Utility Functions without GUI dependencies.
User notifications manager.
s57RegistrarMgr * m_pRegistrarMan
Global instance.
General observable implementation with several specializations.
OCPN_AUIManager * g_pauimgr
Global instance.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Plugin remote repositories installation and Uninstall/list operations.
PlugInManager * g_pi_manager
Global instance.
RoutePoint * pAnchorWatchPoint2
Global instance.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
RoutePoint * pAnchorWatchPoint1
Global instance.
S57 object query result window.
Select * pSelect
Global instance.
Select * pSelectTC
Global instance.
Selected route, segment, waypoint, etc.
SENCThreadManager * g_SencThreadManager
Global instance.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
Access checks for comm devices and dongle.