63#if (defined(OCPN_GHC_FILESYSTEM) || \
64 (defined(__clang_major__) && (__clang_major__ < 15)))
66#include <ghc/filesystem.hpp>
67namespace fs = ghc::filesystem;
71namespace fs = std::filesystem;
74using namespace std::literals::chrono_literals;
76#include <wx/apptrait.h>
77#include <wx/arrimpl.cpp>
78#include <wx/artprov.h>
79#include <wx/aui/aui.h>
80#include <wx/clrpicker.h>
81#include <wx/cmdline.h>
85#include <wx/display.h>
90#include <wx/jsonreader.h>
91#include <wx/listctrl.h>
93#include <wx/printdlg.h>
95#include <wx/progdlg.h>
96#include <wx/settings.h>
97#include <wx/stdpaths.h>
98#include <wx/tokenzr.h>
102#include "model/certificates.h"
105#include "model/comm_n0183_output.h"
106#include "model/comm_vars.h"
109#include "model/instance_check.h"
116#include "model/nav_object_database.h"
117#include "model/navutil_base.h"
119#include "model/own_ship.h"
121#include "model/route.h"
122#include "model/routeman.h"
123#include "model/select.h"
124#include "model/track.h"
128#include "ais_info_gui.h"
142#include "gdal/cpl_csv.h"
150#include "OCPN_AUIManager.h"
151#include "ocpn_frame.h"
152#include "OCPNPlatform.h"
154#include "rest_server_gui.h"
155#include "route_ctx_factory.h"
156#include "routemanagerdialog.h"
157#include "routeman_gui.h"
158#include "RoutePropDlgImpl.h"
161#include "S57QueryDialog.h"
162#include "safe_mode_gui.h"
163#include "SoundFactory.h"
167#include "TrackPropDlg.h"
175#include "model/macutils.h"
179#include "model/garmin_protocol_mgr.h"
180void RedirectIOToConsole();
183#if defined(__WXMSW__) && defined(__MSVC__LEAK)
184#include "Stackwalker.h"
192#include "androidUTIL.h"
198const char *
const kUsage =
201 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
202 opencpn --remote [-R] | -q] | -e] |-o <str>]
204Options for starting opencpn
206 -c, --configdir=<dirpath> Use alternative configuration directory.
207 -p, --portable Run in portable mode.
208 -f, --fullscreen Switch to full screen mode on start.
209 -G, --no_opengl Disable OpenGL video acceleration. This setting will
211 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
212 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
213 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
214 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
215 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
216 Zero or negative <num> specifies no limit.
218 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
219 -W, --config_wizard Start with initial configuration wizard
221Options manipulating already started opencpn
222 -r, --remote Execute commands on already running instance
223 -R, --raise Make running OpenCPN visible if hidden
224 -q, --quit Terminate already running opencpn
225 -e, --get_rest_endpoint Print rest server endpoint and exit.
226 -o, --open=<GPX file> Open file in running opencpn
229 GPX file GPX-formatted file with waypoints or routes.
233wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
234wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
236wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
237wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
238wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
239wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
240wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
241wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
242wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
243wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
244wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
254WX_DEFINE_OBJARRAY(ArrayOfCDI);
257bool g_bUpgradeInProcess;
263LayerList *pLayerList;
264wxString ChartListFileName;
265wxString gDefaultWorldMapLocation;
266wxString *pInit_Chart_Dir;
268wxString g_VisibleLayers;
269wxString g_InvisibleLayers;
270wxString g_VisiNameinLayers;
271wxString g_InVisiNameinLayers;
273int g_FlushNavobjChangesTimeout;
280int g_mem_total, g_mem_initial;
282static unsigned int malloc_max;
284wxDateTime g_start_time;
285wxDateTime g_loglast_time;
286static OcpnSound *_bells_sounds[] = {SoundFactory(), SoundFactory()};
287std::vector<OcpnSound *> bells_sound(_bells_sounds, _bells_sounds + 2);
291bool g_bTransparentToolbar;
292bool g_bTransparentToolbarInOpenGLOK;
294wxArrayPtrVoid *UserColourHashTableArray;
295wxColorHashMap *pcurrent_user_color_hash;
303int g_ChartUpdatePeriod;
305float g_MarkScaleFactorExp;
306int g_last_ChartScaleFactor;
311s57RegistrarMgr *m_pRegistrarMan;
314#include "model/macutils.h"
323extern bool s_glu_dll_ready;
324extern HINSTANCE s_hGLU_DLL;
332long gStart_LMT_Offset;
334wxArrayString *pMessageOnceArray;
338std::vector<std::string> TideCurrentDataSet;
340int options_lastPage = 0;
341int options_subpage = 0;
343wxPoint options_lastWindowPos(0, 0);
344wxSize options_lastWindowSize(0, 0);
350bool GetMemoryStatus(
int *mem_total,
int *mem_used);
353bool g_bDeferredStartTrack;
360#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
361wxLocale *plocale_def_lang = 0;
366int g_AisTargetList_count;
367bool g_bAisTargetList_autosort;
369wxAuiDefaultDockArt *g_pauidockart;
374double gQueryVar = 361.0;
376char bells_sound_file_name[2][12] = {
"1bells.wav",
"2bells.wav"};
378int portaudio_initialized;
380char nmea_tick_chars[] = {
'|',
'/',
'-',
'\\',
'|',
'/',
'-',
'\\'};
382int g_sticky_projection;
384int n_NavMessageShown;
385wxString g_config_version_string;
400wxArrayString g_locale_catalog_array;
401bool b_reloadForPlugins;
402bool g_btrackContinuous;
404bool g_bmasterToolbarFull =
true;
406int g_AndroidVersionCode;
410WX_DEFINE_ARRAY_PTR(
ChartCanvas *, arrayofCanvasPtr);
412arrayofCanvasPtr g_canvasArray;
413wxString g_lastAppliedTemplateGUID;
416bool g_disable_main_toolbar;
417bool g_declutter_anchorage;
418bool g_bhide_route_console;
430DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
431 0x6b, 0xba, 0xe7, 0x22, 0xc0);
435#include <wx/msw/msvcrt.h>
439static const long long lNaN = 0xfff8000000000000;
440#define NAN (*(double *)&lNaN)
444void appendOSDirSlash(wxString *pString);
446void InitializeUserColors(
void);
447void DeInitializeUserColors(
void);
448void SetSystemColors(ColorScheme cs);
450static bool LoadAllPlugIns(
bool load_enabled) {
451 g_Platform->ShowBusySpinner();
452 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
453 g_Platform->HideBusySpinner();
461#if defined(__WXGTK__) || defined(__WXQT__)
462#include "bitmaps/opencpn.xpm"
465wxString newPrivateFileName(wxString,
const char *name,
466 [[maybe_unused]]
const char *windowsName) {
467 wxString fname = wxString::FromUTF8(name);
468 wxString filePathAndName;
471 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
472 filePathAndName.Append(wxFileName::GetPathSeparator());
475 wxString fwname = wxString::FromUTF8(windowsName);
476 filePathAndName.Append(fwname);
478 filePathAndName.Append(fname);
481 return filePathAndName;
490BEGIN_EVENT_TABLE(
MyApp, wxApp)
491EVT_ACTIVATE_APP(MyApp::OnActivateApp)
494static
void ActivateRoute(const std::
string &guid) {
495 Route *route = g_pRouteMan->FindRouteByGUID(guid);
497 wxLogMessage(
"Cannot activate guid: no such route");
500 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
506 point = g_pRouteMan->FindBestActivatePoint(route, gLat, gLon, gCog, gSog);
508 point = route->GetPoint(2);
515static void ReverseRoute(
const std::string &guid) {
516 Route *route = g_pRouteMan->FindRouteByGUID(guid);
518 wxLogMessage(
"Cannot activate guid: no such route");
525void MyApp::InitRestListeners() {
526 auto activate_route = [&](wxCommandEvent ev) {
527 auto guid = ev.GetString().ToStdString();
531 auto reverse_route = [&](wxCommandEvent ev) {
532 auto guid = ev.GetString().ToStdString();
538bool MyApp::OpenFile(
const std::string &path) {
540 auto result = nav_objects.load_file(path.c_str());
542 std::string s(_(
"Cannot load route or waypoint file: "));
543 s += std::string(
"\"") + path +
"\"";
544 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
550 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
552 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
553 pRouteManagerDialog->UpdateLists();
554 LLBBox box = nav_objects.GetBBox();
555 if (box.GetValid()) {
556 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
562void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
565 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
566 parser.AddSwitch(
"p",
"portable");
567 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
568 wxCMD_LINE_PARAM_OPTIONAL);
569 parser.AddSwitch(
"f",
"fullscreen");
570 parser.AddSwitch(
"G",
"no_opengl");
571 parser.AddSwitch(
"W",
"config_wizard");
572 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
573 parser.AddSwitch(
"D",
"rebuild_chart_db");
574 parser.AddSwitch(
"P",
"parse_all_enc");
575 parser.AddOption(
"l",
"loglevel");
576 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
577 parser.AddSwitch(
"U",
"unit_test_2");
578 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
579 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
580 parser.AddSwitch(
"s",
"safe_mode");
581 parser.AddSwitch(
"r",
"remote");
582 parser.AddSwitch(
"R",
"raise");
583 parser.AddSwitch(
"q",
"quit");
584 parser.AddSwitch(
"e",
"get_rest_endpoint");
585 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
586 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
592static void ParseLoglevel(wxCmdLineParser &parser) {
593 wxLog::SetLogLevel(wxLOG_Message);
596static void ParseLoglevel(wxCmdLineParser &parser) {
597 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
598 strLevel = strLevel ? strLevel :
"info";
600 if (parser.Found(
"l", &wxLevel)) {
601 strLevel = wxLevel.c_str();
603 wxLogLevel level = OcpnLog::str2level(strLevel);
604 if (level == OcpnLog::LOG_BADLEVEL) {
605 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
608 wxLog::SetLogLevel(level);
613bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
620bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
625 g_unit_test_2 = parser.Found(
"unit_test_2");
626 g_bportable = parser.Found(
"p");
627 g_start_fullscreen = parser.Found(
"fullscreen");
628 g_bdisable_opengl = parser.Found(
"no_opengl");
629 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
630 g_NeedDBUpdate = parser.Found(
"rebuild_chart_db") ? 2 : 0;
631 g_parse_all_enc = parser.Found(
"parse_all_enc");
632 g_config_wizard = parser.Found(
"config_wizard");
633 if (parser.Found(
"unit_test_1", &number)) {
634 g_unit_test_1 =
static_cast<int>(number);
635 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
637 safe_mode::set_mode(parser.Found(
"safe_mode"));
638 ParseLoglevel(parser);
640 if (parser.Found(
"configdir", &wxstr)) {
641 g_configdir = wxstr.ToStdString();
642 fs::path path(g_configdir);
643 if (!fs::exists(path) || !fs::is_directory(path)) {
644 std::cerr << g_configdir <<
" is not an existing directory.\n";
649 bool has_start_options =
false;
650 static const std::vector<std::string> kStartOptions = {
655 "rebuild_gl_raster_cache",
661 for (
const auto &opt : kStartOptions) {
662 if (parser.Found(opt)) has_start_options =
true;
664 if (has_start_options && parser.Found(
"remote")) {
665 std::cerr <<
"this option is not compatible with --remote\n";
669 bool has_remote_options =
false;
670 static const std::vector<std::string> kRemoteOptions = {
671 "raise",
"quit",
"open",
"get_rest_endpoint"};
672 for (
const auto &opt : kRemoteOptions) {
673 if (parser.Found(opt)) has_remote_options =
true;
675 if (has_remote_options && !parser.Found(
"remote")) {
676 std::cerr <<
"This option requires --remote\n";
680 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
681 g_params.push_back(parser.GetParam(paramNr).ToStdString());
684 if (!parser.Found(
"remote"))
685 m_parsed_cmdline = ParsedCmdline();
686 else if (parser.Found(
"raise"))
687 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
688 else if (parser.Found(
"quit"))
689 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
690 else if (parser.Found(
"get_rest_endpoint"))
691 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
692 else if (parser.Found(
"open", &optarg))
693 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
694 else if (parser.GetParamCount() == 1)
696 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
697 else if (!has_start_options && !has_remote_options) {
699 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
709bool MyApp::OnExceptionInMainLoop() {
710 wxLogWarning(
"Caught MainLoopException, continuing...");
715void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
717static wxStopWatch init_sw;
720 if (m_exitcode != -2)
return m_exitcode;
721 return wxAppConsole::OnRun();
732 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
733 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
734 setenv(
"GDK_BACKEND",
"x11", 1);
738 "mesa_glthread",
"false",
744bool MyApp::OnInit() {
745 if (!wxApp::OnInit())
return false;
747 androidEnableBackButton(
false);
748 androidEnableOptionItems(
false);
753#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
759 wxBitmap bmp(10, 10, -1);
761 dc.SelectObject(bmp);
762 dc.DrawText(
"X", 0, 0);
767 g_BasePlatform = g_Platform;
774 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
778 std::cerr <<
"No remote opencpn found. Giving up.\n";
783 std::unique_ptr<LocalClientApi> client;
785 client = LocalClientApi::GetClient();
787 WARNING_LOG <<
"Ipc client exception: " << ie.str();
794 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
795 "to respond.\nPlease retry."),
796 "OpenCPN", wxICON_INFORMATION | wxOK);
801 auto result = client->HandleCmdline(m_parsed_cmdline.action,
802 m_parsed_cmdline.arg);
806 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
815 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
816 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
821 if (!safe_mode::get_mode()) {
827 OCPNPlatform::Initialize_1();
832 MyApp::SetAppDisplayName(
"OpenCPN");
835 wxDateTime x = wxDateTime::UNow();
836 long seed = x.GetMillisecond();
837 seed *= x.GetTicks();
842 setlocale(LC_NUMERIC,
"C");
844 g_start_time = wxDateTime::Now();
846 g_loglast_time = g_start_time;
847 g_loglast_time.MakeGMT();
848 g_loglast_time.Subtract(
849 wxTimeSpan(0, 29, 0, 0));
851 AnchorPointMinDist = 5.0;
857 GetMemoryStatus(&g_mem_total, &g_mem_initial);
861 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
862 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
863 wxFONTENCODING_SYSTEM);
864 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
867 auto ¬eman = NotificationManager::GetInstance();
868 noteman.ScrubNotificationDirectory(30);
871 if (!g_Platform->InitializeLogFile()) {
883 wxLogMessage(
"\n\n________\n");
885 wxDateTime now = wxDateTime::Now();
886 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
887 now.FormatISODate().mb_str().data());
888 wxLogLevel level = wxLog::GetLogLevel();
889 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
891 wxString wxver(wxVERSION_STRING);
892 wxver.Prepend(
"wxWidgets version: ");
894 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
898 os_name = platforminfo.GetOperatingSystemIdName();
900 os_name = platforminfo.GetOperatingSystemFamilyName();
903 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
904 platforminfo.GetPortIdName();
906 wxLogMessage(wxver +
" " + platform);
908 ::wxGetOsVersion(&osMajor, &osMinor);
909 wxString osVersionMsg;
910 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
911 wxLogMessage(osVersionMsg);
913 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
914 g_mem_total / 1024, g_mem_initial / 1024);
919 if (!detail->osd_names_like.empty())
920 like0 = detail->osd_names_like[0].c_str();
921 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
922 detail->osd_arch.c_str(), detail->osd_name.c_str(),
923 detail->osd_version.c_str(), detail->osd_ID.c_str(),
925 wxLogMessage(msgplat);
927 wxString imsg =
"SData_Locn is ";
928 imsg += g_Platform->GetSharedDataDir();
932 ::wxInitAllImageHandlers();
936 prepareAndroidStyleSheets();
940 pInit_Chart_Dir =
new wxString();
945 imsg =
"PrivateDataDir is ";
951 pMessageOnceArray =
new wxArrayString;
955 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
959 pSelect->SetSelectPixelRadius(12);
964 pSelectTC->SetSelectPixelRadius(25);
967 pSelectAIS =
new Select();
968 pSelectAIS->SetSelectPixelRadius(12);
972 g_pais_query_dialog_active = NULL;
975 g_hostname = ::wxGetHostName();
976 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
978 androidGetDeviceInfo();
979 g_hostname = wxString(
"Android-") + g_android_Device_Model;
980 g_hostname.Replace(
" ",
"-",
true);
985 wxString p(
"Portable-");
986 g_hostname = p + g_hostname;
991 pLayerList =
new LayerList;
993 pRouteList =
new RouteList;
996 auto &navobj_db = NavObj_dB::GetInstance();
1003#ifdef PROBE_PORTS__WITH_HELPER
1004 user_user_id = getuid();
1005 file_user_id = geteuid();
1009 bool b_initial_load =
false;
1011 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
1012 if (config_test_file_name.FileExists())
1013 wxLogMessage(
"Using existing Config_File: " +
1014 g_Platform->GetConfigFileName());
1017 wxLogMessage(
"Creating new Config_File: " +
1018 g_Platform->GetConfigFileName());
1020 b_initial_load =
true;
1023 config_test_file_name.DirExists(config_test_file_name.GetPath()))
1024 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
1025 wxLogMessage(
"Cannot create config file directory for " +
1026 g_Platform->GetConfigFileName());
1031 pConfig = g_Platform->GetConfigObject();
1032 InitBaseConfig(pConfig);
1033 pConfig->LoadMyConfig();
1037 if (b_initial_load) g_Platform->SetDefaultOptions();
1039 g_Platform->applyExpertMode(g_bUIexpert);
1047 g_StyleManager->SetStyle(
"MUI_flat");
1048 if (!g_StyleManager->IsOK()) {
1049 wxString msg = _(
"Failed to initialize the user interface. ");
1050 msg << _(
"OpenCPN cannot start. ");
1051 msg << _(
"The necessary configuration files were not found. ");
1052 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
1053 << _(
" for details.") <<
"\n\n";
1054 msg << g_Platform->GetSharedDataDir();
1056 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
1057 wxCANCEL | wxICON_ERROR);
1064 if (style) style->chartStatusWindowTransparent =
true;
1068 pWayPointMan = NULL;
1072 msg.Printf(
"Detected display size (horizontal): %d mm",
1077 if (g_config_display_size_manual &&
1082 msg.Printf(
"Display size (horizontal) config override: %d mm",
1091 int SelectPixelRadius = 50;
1093 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1094 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1095 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1099 if (!n_NavMessageShown) {
1106#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1109 g_Platform->SetLocaleSearchPrefixes();
1111 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1113 imsg =
"System default Language: " + def_lang_canonical;
1116 wxString cflmsg =
"Config file language: " + g_locale;
1117 wxLogMessage(cflmsg);
1119 if (g_locale.IsEmpty()) {
1120 g_locale = def_lang_canonical;
1121 cflmsg =
"Config file language empty, using system default: " + g_locale;
1122 wxLogMessage(cflmsg);
1126 g_locale = g_Platform->GetAdjustedAppLocale();
1127 cflmsg =
"Adjusted App language: " + g_locale;
1128 wxLogMessage(cflmsg);
1131 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1133 imsg =
"Opencpn language set to: ";
1140 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1142 wxLogMessage(
"wxLocale support not available");
1147 if (g_config_wizard || b_initial_load) {
1149 auto res = wiz.Run();
1160 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1161 g_bUpgradeInProcess = (vs != g_config_version_string);
1163 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1166 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1167 wxLogMessage(g_Platform->GetLargeLogMessage());
1172 g_bdisable_opengl =
true;
1176 if (g_bdisable_opengl) g_bopengl =
false;
1178#if defined(__linux__) && !defined(__ANDROID__)
1179 if (g_bSoftwareGL) {
1180 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1193 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1195 wxMin(g_memCacheLimit, 1024 * 1024);
1201 g_memCacheLimit = 0;
1202 if (0 == g_nCacheLimit)
1203 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1208 "chartlist.dat",
"CHRTLIST.DAT");
1212 "mmsitoname.csv",
"MMSINAME.CSV");
1215 if (pInit_Chart_Dir->IsEmpty()) {
1216 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1220 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1222 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1226 InitRestListeners();
1229 gDefaultWorldMapLocation =
"gshhs";
1230 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1231 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1232 if (gWorldMapLocation == wxEmptyString) {
1233 gWorldMapLocation = gDefaultWorldMapLocation;
1238 wxString default_tcdata0 =
1239 (g_Platform->GetSharedDataDir() +
"tcdata" +
1240 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1241 wxString default_tcdata1 =
1242 (g_Platform->GetSharedDataDir() +
"tcdata" +
1243 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1245 if (TideCurrentDataSet.empty()) {
1246 TideCurrentDataSet.push_back(
1247 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1248 TideCurrentDataSet.push_back(
1249 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1254 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1255 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1256 wxFileName::GetPathSeparator() +
"2bells.wav");
1257 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1262 g_Platform->Initialize_2();
1266 wxSize new_frame_size(-1, -1);
1268 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1270 InitializeUserColors();
1272 auto style = g_StyleManager->GetCurrentStyle();
1273 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1275 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1277 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1279 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1280 (g_nframewin_y <= ch))
1281 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1283 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1289 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1290 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1291 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1292 g_bframemax =
false;
1295 g_lastClientRectx = cx;
1296 g_lastClientRecty = cy;
1297 g_lastClientRectw = cw;
1298 g_lastClientRecth = ch;
1301 wxPoint position(0, 0);
1302 wxSize dsize = wxGetDisplaySize();
1305 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1308 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1309 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1314 frame_rect.left = position.x;
1315 frame_rect.top = position.y;
1316 frame_rect.right = position.x + new_frame_size.x;
1317 frame_rect.bottom = position.y + new_frame_size.y;
1321 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1322 position = wxPoint(10, 10);
1327 const wxPoint ptScreen(position.x, position.y);
1328 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1330 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1333 g_nframewin_posx = position.x;
1334 g_nframewin_posy = position.y;
1337 wxSize asz = getAndroidDisplayDimensions();
1342 if ((cw > 200) && (ch > 200))
1343 new_frame_size.Set(cw, ch);
1345 new_frame_size.Set(800, 400);
1349 long app_style = wxDEFAULT_FRAME_STYLE;
1350 app_style |= wxWANTS_CHARS;
1355 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1356 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1359 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1360 myframe_window_title += g_Platform->GetHomeDir();
1361 myframe_window_title +=
"]";
1365 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1366 new_frame_size.x, new_frame_size.y, position.x, position.y);
1369 gFrame =
new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1371 wxTheApp->SetTopWindow(gFrame);
1374 g_Platform->Initialize_3();
1381 g_pauidockart =
new wxAuiDefaultDockArt;
1382 g_pauimgr->SetArtProvider(g_pauidockart);
1383 g_pauimgr->SetDockSizeConstraint(.9, .9);
1388 g_pauimgr->SetManagedWindow(gFrame);
1390 gFrame->CreateCanvasLayout();
1394 gFrame->SetChartUpdatePeriod();
1398 gFrame->GetPrimaryCanvas()->SetFocus();
1400 pthumbwin =
new ThumbWin(gFrame->GetPrimaryCanvas());
1402 gFrame->ApplyGlobalSettings(
false);
1404 gFrame->SetAllToolbarScale();
1410 gFrame->SetAndApplyColorScheme(global_color_scheme);
1412 if (g_bframemax) gFrame->Maximize(
true);
1415 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->GetPixPerMM() > 4.0))
1416 gFrame->Maximize(
true);
1423 ArrayOfCDI ChartDirArray;
1424 pConfig->LoadChartDirArray(ChartDirArray);
1429 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1432 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1433 if (RegKey.Exists()) {
1435 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1437 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1439 wxStringTokenizer tkz(dirs,
";");
1440 while (tkz.HasMoreTokens()) {
1441 wxString token = tkz.GetNextToken();
1444 cdi.fullpath = token.Trim();
1445 cdi.magic_number =
"";
1447 ChartDirArray.Add(cdi);
1454 cdi.fullpath =
"charts";
1455 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1456 cdi.magic_number =
"";
1457 ChartDirArray.Add(cdi);
1461 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1471 if (!ChartDirArray.GetCount())
1472 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1476 if (g_NeedDBUpdate == 0 &&
1482 if (g_restore_dbindex >= 0) {
1483 if (
ChartData->GetChartTableEntries() == 0)
1484 g_restore_dbindex = -1;
1486 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1487 g_restore_dbindex = 0;
1499 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1500 g_GLOptions.m_bTextureCompressionCaching) {
1501 gFrame->ReloadAllVP();
1520 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1521 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1524 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1525 wxLogMessage(dogmsg);
1527 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1535 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1537 pAnchorWatchPoint1 = NULL;
1538 pAnchorWatchPoint2 = NULL;
1542 gFrame->DoChartUpdate();
1547 gFrame->ReloadAllVP();
1549 gFrame->Refresh(
false);
1552 gFrame->GetPrimaryCanvas()->Enable();
1553 gFrame->GetPrimaryCanvas()->SetFocus();
1560 if (!g_bdisable_opengl) {
1563 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1564 gFrame->m_defer_size = gFrame->GetSize();
1565 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1566 g_pauimgr->Update();
1567 gFrame->m_bdefer_resize =
true;
1577 glDeleteTextures(n, texts);
1583 if (g_start_fullscreen) gFrame->ToggleFullScreen();
1588 gFrame->SetSize(getAndroidDisplayDimensions());
1589 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1593 gFrame->GetPrimaryCanvas()->Enable();
1594 gFrame->GetPrimaryCanvas()->SetFocus();
1602 gFrame->FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
1605 gFrame->FrameCOGTimer.Start(2000, wxTIMER_CONTINUOUS);
1608 gFrame->FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
1613 OCPNPlatform::Initialize_4();
1616 androidHideBusyIcon();
1619 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1627 if (!n_NavMessageShown || (vs != g_config_version_string) ||
1628 (g_AndroidVersionCode != androidGetVersionCode())) {
1632 if (!ShowNavWarning()) {
1633 qDebug() <<
"Closing due to NavWarning Cancel";
1639 n_NavMessageShown = 1;
1643 g_AndroidVersionCode = androidGetVersionCode();
1644 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
1649 if (!n_NavMessageShown || (vs != g_config_version_string)) {
1650 if (!ShowNavWarning())
return false;
1651 n_NavMessageShown = 1;
1658 g_bHasHwClock =
true;
1659#if defined(__UNIX__) && !defined(__ANDROID__)
1662 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1663 (stat(
"/dev/misc/rtc", &buffer) == 0));
1666 g_config_version_string = vs;
1669 pConfig->UpdateSettings();
1672 gFrame->InitTimer.Start(5, wxTIMER_CONTINUOUS);
1674 g_pauimgr->Update();
1676 for (
auto *cp : TheConnectionParams()) {
1678 if (cp->GetDSPort().Contains(
"Serial")) {
1679 std::string port(cp->Port.ToStdString());
1687 m_comm_bridge.Initialize();
1689 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1692 if (ipv4_addrs.size()) {
1693 std::string ipAddr = ipv4_addrs[0];
1696 if (data_dir.Last() != wxFileName::GetPathSeparator())
1697 data_dir.Append(wxFileName::GetPathSeparator());
1699 make_certificate(ipAddr, data_dir.ToStdString());
1701 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1702 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1708int MyApp::OnExit() {
1709 wxLogMessage(
"opencpn::MyApp starting exit.");
1711 m_usb_watcher.Stop();
1714 wxDateTime lognow = wxDateTime::Now();
1716 wxString day = lognow.FormatISODate();
1717 wxString utc = lognow.FormatISOTime();
1718 wxString navmsg =
"LOGBOOK: ";
1726 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ", gLat, gLon);
1730 if (std::isnan(gCog))
1731 cog.Printf(
"COG ----- ");
1733 cog.Printf(
"COG %10.5f ", gCog);
1736 if (std::isnan(gSog))
1737 sog.Printf(
"SOG ----- ");
1739 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(gSog));
1746 data.Printf(
"OFF: Lat %10.5f Lon %10.5f", gLat, gLon);
1749 wxLogMessage(navmsg);
1750 g_loglast_time = lognow;
1752 if (ptcmgr)
delete ptcmgr;
1754 for (
Track *track : g_TrackList) {
1757 g_TrackList.clear();
1765 delete g_SencThreadManager;
1768 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1777 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1778 wxLog::FlushActive();
1780 g_Platform->CloseLogFile();
1782 delete pInit_Chart_Dir;
1784 for (
Track *track : g_TrackList) {
1787 g_TrackList.clear();
1790 delete pWayPointMan;
1792 delete pMessageOnceArray;
1794 DeInitializeUserColors();
1798 delete m_pRegistrarMan;
1801 delete g_StyleManager;
1806 if (s_glu_dll_ready) {
1807 FreeLibrary(s_hGLU_DLL);
1816 void RestoreSystemColors(
void);
1817 RestoreSystemColors();
1824#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1825 if (plocale_def_lang)
delete plocale_def_lang;
1828 FontMgr::Shutdown();
1830 g_Platform->OnExit_2();
1837#ifdef LINUX_CRASHRPT
1838void MyApp::OnFatalException() { g_crashprint.Report(); }
1844void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1849 if (eErrClass == CE_Debug)
1850 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1851 else if (eErrClass == CE_Warning)
1852 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1854 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1856 wxString str(msg, wxConvUTF8);
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetListDialog.
Class AISTargetQueryDialog.
Chart canvas configuration state
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Generic Chart canvas base.
Extends AboutFrame, providing implementation for various event handlers and additional methods.
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.
Handles the AIS information GUI and sound alerts.
ChartCanvas - Main chart display and interaction component.
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.
The CommBridge class and helpers.
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.
Miscellaneous globals primarely used by gui 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.
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.
Class NotificationManager.
General observable implementation with several specializations.
PLugin remote repositories installation and Uninstall/list operations.
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.