53#include <wx/msw/msvcrt.h>
65#if defined(__WXMSW__) && defined(__MSVC__LEAK)
66#include "Stackwalker.h"
75#include <wx/apptrait.h>
76#include <wx/arrimpl.cpp>
77#include <wx/artprov.h>
78#include <wx/aui/aui.h>
79#include <wx/aui/dockart.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>
100#include "o_sound/o_sound.h"
118#include "model/nav_object_database.h"
130#include "ais_info_gui.h"
142#include "dialog_alert.h"
145#include "gdal/cpl_csv.h"
159#include "route_ctx_factory.h"
166#include "safe_mode_gui.h"
167#include "std_filesystem.h"
185void RedirectIOToConsole();
197#include "androidUTIL.h"
202using namespace std::literals::chrono_literals;
204const char *
const kUsage =
207 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
208 opencpn --remote [-R] | -q] | -e] |-o <str>]
210Options for starting opencpn
212 -c, --configdir=<dirpath> Use alternative configuration directory.
213 -p, --portable Run in portable mode.
214 -f, --fullscreen Switch to full screen mode on start.
215 -G, --no_opengl Disable OpenGL video acceleration. This setting will
217 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
218 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
219 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
220 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
221 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
222 Zero or negative <num> specifies no limit.
224 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
225 -W, --config_wizard Start with initial configuration wizard
227Options manipulating already started opencpn
228 -r, --remote Execute commands on already running instance
229 -R, --raise Make running OpenCPN visible if hidden
230 -q, --quit Terminate already running opencpn
231 -e, --get_rest_endpoint Print rest server endpoint and exit.
232 -o, --open=<GPX file> Open file in running opencpn
235 GPX file GPX-formatted file with waypoints or routes.
239wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
240wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
242wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
243wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
244wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
245wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
246wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
247wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
248wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
249wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
250wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
260WX_DEFINE_OBJARRAY(ArrayOfCDI);
262static int user_user_id;
263static int file_user_id;
265static int g_mem_total, g_mem_initial;
267static unsigned int malloc_max;
269static int osMajor, osMinor;
271static bool g_bHasHwClock;
273#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
275wxLocale *plocale_def_lang = 0;
283extern sigjmp_buf env;
288DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
289 0x6b, 0xba, 0xe7, 0x22, 0xc0);
293static const long long lNaN = 0xfff8000000000000;
294#define NAN (*(double *)&lNaN)
298void appendOSDirSlash(wxString *pString);
300void InitializeUserColors();
301void DeInitializeUserColors();
302void SetSystemColors(ColorScheme cs);
304static bool LoadAllPlugIns(
bool load_enabled) {
305 g_Platform->ShowBusySpinner();
306 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
307 g_Platform->HideBusySpinner();
315#if defined(__WXGTK__) || defined(__WXQT__)
316#include "bitmaps/opencpn.xpm"
319wxString newPrivateFileName(wxString,
const char *name,
320 [[maybe_unused]]
const char *windowsName) {
321 wxString fname = wxString::FromUTF8(name);
322 wxString filePathAndName;
325 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
326 filePathAndName.Append(wxFileName::GetPathSeparator());
329 wxString fwname = wxString::FromUTF8(windowsName);
330 filePathAndName.Append(fwname);
332 filePathAndName.Append(fname);
335 return filePathAndName;
341 : wxFrame(
nullptr, wxID_ANY,
"Loading...", wxDefaultPosition,
342 wxSize(900, 600), wxSTAY_ON_TOP) {
344 SetBackgroundColour(wxColour(0, 0, 0));
348 new wxStaticText(
this, wxID_ANY,
"", wxDefaultPosition, wxDefaultSize,
349 wxALIGN_CENTRE_HORIZONTAL);
350 text->SetForegroundColour(wxColour(255, 255, 255));
352 wxBoxSizer *sizer =
new wxBoxSizer(wxVERTICAL);
353 sizer->Add(text, 1, wxALIGN_CENTER);
354 SetSizerAndFit(sizer);
360bool ShowNavWarning() {
363OpenCPN is distributed in the hope that it will be useful, \
364but WITHOUT ANY WARRANTY; without even the implied \
365warranty of MERCHANTABILITY or FITNESS FOR A \
366PARTICULAR PURPOSE.\n\n\
367See the GNU General Public License for more details.\n\n\
368OpenCPN must only be used in conjunction with approved \
369paper charts and traditional methods of navigation.\n\n\
370DO NOT rely upon OpenCPN for safety of life or property.\n\n\
371Please click \"Agree\" and proceed, or \"Cancel\" to quit.\n"));
373 wxString vs = wxString::Format(
" .. Version %s", VERSION_FULL);
376 androidShowDisclaimer(_(
"OpenCPN for Android") + vs, msg);
379 msg.Replace(
"\n",
"<br>");
381 std::stringstream html;
382 html <<
"<html><body><p>";
383 html << msg.ToStdString();
384 html <<
"</p></body></html>";
386 std::string title = _(
"Welcome to OpenCPN").ToStdString();
387 std::string action = _(
"Agree").ToStdString();
389 info_dlg.SetInitialSize();
390 info_dlg.AddHtmlContent(html);
391 int agreed = info_dlg.ShowModal();
392 return agreed == wxID_OK;
396bool DoNavMessage(wxString &new_version_string) {
401 if (!n_NavMessageShown || (new_version_string != g_config_version_string) ||
402 (g_AndroidVersionCode != androidGetVersionCode())) {
406 if (!ShowNavWarning()) {
407 qDebug() <<
"Closing due to NavWarning Cancel";
413 n_NavMessageShown = 1;
417 g_AndroidVersionCode = androidGetVersionCode();
418 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
423 if (!n_NavMessageShown || (new_version_string != g_config_version_string)) {
424 if (!ShowNavWarning())
return false;
425 n_NavMessageShown = 1;
438BEGIN_EVENT_TABLE(
MyApp, wxApp)
439EVT_ACTIVATE_APP(MyApp::OnActivateApp)
442static
void ActivateRoute(const std::
string &guid) {
445 wxLogMessage(
"Cannot activate guid: no such route");
456 point = route->GetPoint(2);
463static void ReverseRoute(
const std::string &guid) {
466 wxLogMessage(
"Cannot activate guid: no such route");
473void MyApp::InitRestListeners() {
474 auto activate_route = [&](wxCommandEvent ev) {
475 auto guid = ev.GetString().ToStdString();
479 auto reverse_route = [&](wxCommandEvent ev) {
480 auto guid = ev.GetString().ToStdString();
486bool MyApp::OpenFile(
const std::string &path) {
488 auto result = nav_objects.load_file(path.c_str());
490 std::string s(_(
"Cannot load route or waypoint file: "));
491 s += std::string(
"\"") + path +
"\"";
492 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
498 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
500 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
501 pRouteManagerDialog->UpdateLists();
502 LLBBox box = nav_objects.GetBBox();
503 if (box.GetValid()) {
504 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
510void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
513 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
514 parser.AddSwitch(
"p",
"portable");
515 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
516 wxCMD_LINE_PARAM_OPTIONAL);
517 parser.AddSwitch(
"f",
"fullscreen");
518 parser.AddSwitch(
"G",
"no_opengl");
519 parser.AddSwitch(
"W",
"config_wizard");
520 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
521 parser.AddSwitch(
"D",
"rebuild_chart_db");
522 parser.AddSwitch(
"P",
"parse_all_enc");
523 parser.AddOption(
"l",
"loglevel");
524 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
525 parser.AddSwitch(
"U",
"unit_test_2");
526 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
527 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
528 parser.AddSwitch(
"s",
"safe_mode");
529 parser.AddSwitch(
"r",
"remote");
530 parser.AddSwitch(
"R",
"raise");
531 parser.AddSwitch(
"q",
"quit");
532 parser.AddSwitch(
"e",
"get_rest_endpoint");
533 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
534 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
540static void ParseLoglevel(wxCmdLineParser &parser) {
541 wxLog::SetLogLevel(wxLOG_Message);
544static void ParseLoglevel(wxCmdLineParser &parser) {
545 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
546 strLevel = strLevel ? strLevel :
"info";
548 if (parser.Found(
"l", &wxLevel)) {
549 strLevel = wxLevel.c_str();
551 wxLogLevel level = OcpnLog::str2level(strLevel);
552 if (level == OcpnLog::LOG_BADLEVEL) {
553 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
556 wxLog::SetLogLevel(level);
561bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
568bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
573 g_unit_test_2 = parser.Found(
"unit_test_2");
574 g_bportable = parser.Found(
"p");
575 g_start_fullscreen = parser.Found(
"fullscreen");
576 g_bdisable_opengl = parser.Found(
"no_opengl");
577 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
579 g_parse_all_enc = parser.Found(
"parse_all_enc");
580 g_config_wizard = parser.Found(
"config_wizard");
581 if (parser.Found(
"unit_test_1", &number)) {
582 g_unit_test_1 =
static_cast<int>(number);
583 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
585 safe_mode::set_mode(parser.Found(
"safe_mode"));
586 ParseLoglevel(parser);
588 if (parser.Found(
"configdir", &wxstr)) {
589 g_configdir = wxstr.ToStdString();
590 fs::path path(g_configdir);
591 if (!fs::exists(path) || !fs::is_directory(path)) {
592 std::cerr << g_configdir <<
" is not an existing directory.\n";
597 bool has_start_options =
false;
598 static const std::vector<std::string> kStartOptions = {
603 "rebuild_gl_raster_cache",
609 for (
const auto &opt : kStartOptions) {
610 if (parser.Found(opt)) has_start_options =
true;
612 if (has_start_options && parser.Found(
"remote")) {
613 std::cerr <<
"this option is not compatible with --remote\n";
617 bool has_remote_options =
false;
618 static const std::vector<std::string> kRemoteOptions = {
619 "raise",
"quit",
"open",
"get_rest_endpoint"};
620 for (
const auto &opt : kRemoteOptions) {
621 if (parser.Found(opt)) has_remote_options =
true;
623 if (has_remote_options && !parser.Found(
"remote")) {
624 std::cerr <<
"This option requires --remote\n";
628 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
629 g_params.push_back(parser.GetParam(paramNr).ToStdString());
632 if (!parser.Found(
"remote"))
633 m_parsed_cmdline = ParsedCmdline();
634 else if (parser.Found(
"raise"))
635 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
636 else if (parser.Found(
"quit"))
637 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
638 else if (parser.Found(
"get_rest_endpoint"))
639 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
640 else if (parser.Found(
"open", &optarg))
641 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
642 else if (parser.GetParamCount() == 1)
644 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
645 else if (!has_start_options && !has_remote_options) {
647 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
657bool MyApp::OnExceptionInMainLoop() {
658 wxLogWarning(
"Caught MainLoopException, continuing...");
663void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
665static wxStopWatch init_sw;
668 if (m_exitcode != -2)
return m_exitcode;
669 return wxAppConsole::OnRun();
680 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
681 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
682 setenv(
"GDK_BACKEND",
"x11", 1);
686 "mesa_glthread",
"false",
695 if (!wxApp::OnInit())
return false;
698 androidEnableBackButton(
false);
699 androidEnableOptionItems(
false);
704#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
710 wxBitmap bmp(10, 10, -1);
712 dc.SelectObject(bmp);
713 dc.DrawText(
"X", 0, 0);
725 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
729 std::cerr <<
"No remote opencpn found. Giving up.\n";
734 std::unique_ptr<LocalClientApi> client;
736 client = LocalClientApi::GetClient();
738 WARNING_LOG <<
"Ipc client exception: " << ie.str();
745 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
746 "to respond.\nPlease retry."),
747 "OpenCPN", wxICON_INFORMATION | wxOK);
752 auto result = client->HandleCmdline(m_parsed_cmdline.action,
753 m_parsed_cmdline.arg);
757 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
766 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
767 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
772 if (!safe_mode::get_mode()) {
778 OCPNPlatform::Initialize_1();
783 MyApp::SetAppDisplayName(
"OpenCPN");
786 wxDateTime x = wxDateTime::UNow();
787 long seed = x.GetMillisecond();
788 seed *= x.GetTicks();
793 setlocale(LC_NUMERIC,
"C");
795 g_start_time = wxDateTime::Now();
797 g_loglast_time = g_start_time;
798 g_loglast_time.MakeGMT();
799 g_loglast_time.Subtract(
800 wxTimeSpan(0, 29, 0, 0));
802 AnchorPointMinDist = 5.0;
808 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
812 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
813 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
814 wxFONTENCODING_SYSTEM);
815 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
818 auto ¬eman = NotificationManager::GetInstance();
819 noteman.ScrubNotificationDirectory(30);
822 if (!g_Platform->InitializeLogFile()) {
834 wxLogMessage(
"\n\n________\n");
836 wxDateTime now = wxDateTime::Now();
837 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
838 now.FormatISODate().mb_str().data());
839 wxLogLevel level = wxLog::GetLogLevel();
840 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
842 wxString wxver(wxVERSION_STRING);
843 wxver.Prepend(
"wxWidgets version: ");
845 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
849 os_name = platforminfo.GetOperatingSystemIdName();
851 os_name = platforminfo.GetOperatingSystemFamilyName();
854 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
855 platforminfo.GetPortIdName();
857 wxLogMessage(wxver +
" " + platform);
859 ::wxGetOsVersion(&osMajor, &osMinor);
860 wxString osVersionMsg;
861 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
862 wxLogMessage(osVersionMsg);
864 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
865 g_mem_total / 1024, g_mem_initial / 1024);
870 if (!detail->osd_names_like.empty())
871 like0 = detail->osd_names_like[0].c_str();
872 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
873 detail->osd_arch.c_str(), detail->osd_name.c_str(),
874 detail->osd_version.c_str(), detail->osd_ID.c_str(),
876 wxLogMessage(msgplat);
878 wxString imsg =
"SData_Locn is ";
879 imsg += g_Platform->GetSharedDataDir();
883 ::wxInitAllImageHandlers();
887 prepareAndroidStyleSheets();
891 pInit_Chart_Dir =
new wxString();
896 imsg =
"PrivateDataDir is ";
902 navutil::InitGlobals();
906 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
910 pSelect->SetSelectPixelRadius(12);
923 g_pais_query_dialog_active = NULL;
926 g_hostname = ::wxGetHostName();
927 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
929 androidGetDeviceInfo();
930 g_hostname = wxString(
"Android-") + g_android_Device_Model;
931 g_hostname.Replace(
" ",
"-",
true);
936 wxString p(
"Portable-");
937 g_hostname = p + g_hostname;
942 pLayerList =
new LayerList;
947 auto &navobj_db = NavObj_dB::GetInstance();
954#ifdef PROBE_PORTS__WITH_HELPER
955 user_user_id = getuid();
956 file_user_id = geteuid();
960 bool b_initial_load =
false;
962 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
963 if (config_test_file_name.FileExists())
964 wxLogMessage(
"Using existing Config_File: " +
965 g_Platform->GetConfigFileName());
968 wxLogMessage(
"Creating new Config_File: " +
969 g_Platform->GetConfigFileName());
971 b_initial_load =
true;
974 config_test_file_name.DirExists(config_test_file_name.GetPath()))
975 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
976 wxLogMessage(
"Cannot create config file directory for " +
977 g_Platform->GetConfigFileName());
982 pConfig = g_Platform->GetConfigObject();
983 InitBaseConfig(pConfig);
984 pConfig->LoadMyConfig();
986 if (g_kiosk_startup) {
988 g_wallpaper->ShowFullScreen(
true);
994 if (b_initial_load) g_Platform->SetDefaultOptions();
996 g_Platform->applyExpertMode(g_bUIexpert);
1001 g_StyleManager->SetStyle(
"MUI_flat");
1002 if (!g_StyleManager->IsOK()) {
1003 wxString msg = _(
"Failed to initialize the user interface. ");
1004 msg << _(
"OpenCPN cannot start. ");
1005 msg << _(
"The necessary configuration files were not found. ");
1006 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
1007 << _(
" for details.") <<
"\n\n";
1008 msg << g_Platform->GetSharedDataDir();
1010 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
1011 wxCANCEL | wxICON_ERROR);
1018 if (style) style->chartStatusWindowTransparent =
true;
1022 pWayPointMan = NULL;
1026 msg.Printf(
"Detected display size (horizontal): %d mm",
1031 if (g_config_display_size_manual &&
1036 msg.Printf(
"Display size (horizontal) config override: %d mm",
1045 int SelectPixelRadius = 50;
1047 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1048 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1049 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1053 if (!n_NavMessageShown) {
1060#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1063 g_Platform->SetLocaleSearchPrefixes();
1065 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1067 imsg =
"System default Language: " + def_lang_canonical;
1070 wxString cflmsg =
"Config file language: " + g_locale;
1071 wxLogMessage(cflmsg);
1073 if (g_locale.IsEmpty()) {
1074 g_locale = def_lang_canonical;
1075 cflmsg =
"Config file language empty, using system default: " + g_locale;
1076 wxLogMessage(cflmsg);
1080 g_locale = g_Platform->GetAdjustedAppLocale();
1081 cflmsg =
"Adjusted App language: " + g_locale;
1082 wxLogMessage(cflmsg);
1085 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1087 imsg =
"Opencpn language set to: ";
1094 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1096 wxLogMessage(
"wxLocale support not available");
1101 if (g_config_wizard || b_initial_load) {
1103 auto res = wiz.Run();
1114 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1115 g_bUpgradeInProcess = (vs != g_config_version_string);
1117 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1120 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1121 wxLogMessage(g_Platform->GetLargeLogMessage());
1126 g_bdisable_opengl =
true;
1129 if (g_bdisable_opengl) g_bopengl =
false;
1131#if defined(__linux__) && !defined(__ANDROID__)
1132 if (g_bSoftwareGL) {
1133 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1146 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1148 wxMin(g_memCacheLimit, 1024 * 1024);
1154 g_memCacheLimit = 0;
1155 if (0 == g_nCacheLimit)
1156 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1161 "chartlist.dat",
"CHRTLIST.DAT");
1165 "mmsitoname.csv",
"MMSINAME.CSV");
1168 if (pInit_Chart_Dir->IsEmpty()) {
1169 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1173 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1175 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1179 InitRestListeners();
1182 gDefaultWorldMapLocation =
"gshhs";
1183 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1184 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1185 if (gWorldMapLocation == wxEmptyString) {
1186 gWorldMapLocation = gDefaultWorldMapLocation;
1191 wxString default_tcdata0 =
1192 (g_Platform->GetSharedDataDir() +
"tcdata" +
1193 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1194 wxString default_tcdata1 =
1195 (g_Platform->GetSharedDataDir() +
"tcdata" +
1196 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1198 if (TideCurrentDataSet.empty()) {
1199 TideCurrentDataSet.push_back(
1200 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1201 TideCurrentDataSet.push_back(
1202 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1207 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1208 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1209 wxFileName::GetPathSeparator() +
"2bells.wav");
1210 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1215 g_Platform->Initialize_2();
1217 LoadChartDatabase();
1221 g_kiosk_startup =
false;
1225 if (!g_kiosk_startup) {
1227 SetTopWindow(gFrame);
1232 gFrame->InitTimer.Start(50, wxTIMER_CONTINUOUS);
1238 OCPNPlatform::Initialize_4();
1241 androidHideBusyIcon();
1244 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1248 if (!g_kiosk_startup) {
1249 if (!DoNavMessage(vs)) {
1256 g_bHasHwClock =
true;
1257#if defined(__UNIX__) && !defined(__ANDROID__)
1260 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1261 (stat(
"/dev/misc/rtc", &buffer) == 0));
1264 g_config_version_string = vs;
1267 pConfig->UpdateSettings();
1269 for (
auto *cp : TheConnectionParams()) {
1271 if (cp->GetDSPort().Contains(
"Serial")) {
1272 std::string port(cp->Port.ToStdString());
1280 m_comm_bridge.Initialize();
1282 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1285 if (ipv4_addrs.size()) {
1286 std::string ipAddr = ipv4_addrs[0];
1289 if (data_dir.Last() != wxFileName::GetPathSeparator())
1290 data_dir.Append(wxFileName::GetPathSeparator());
1292 make_certificate(ipAddr, data_dir.ToStdString());
1294 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1295 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1306 g_wallpaper->Show(
false);
1309 gFrame->ShowFullScreen(
true);
1312 g_wallpaper->Destroy();
1313 g_wallpaper =
nullptr;
1315 SetTopWindow(gFrame);
1318 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1319 if (!DoNavMessage(vs)) {
1324 gFrame->InitTimer.Start(50, wxTIMER_CONTINUOUS);
1330 wxSize new_frame_size(-1, -1);
1332 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1334 InitializeUserColors();
1336 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1337 (g_nframewin_y <= ch))
1338 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1340 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1346 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1347 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1348 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1349 g_bframemax =
false;
1352 g_lastClientRectx = cx;
1353 g_lastClientRecty = cy;
1354 g_lastClientRectw = cw;
1355 g_lastClientRecth = ch;
1358 wxPoint position(0, 0);
1359 wxSize dsize = wxGetDisplaySize();
1362 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1365 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1366 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1371 frame_rect.left = position.x;
1372 frame_rect.top = position.y;
1373 frame_rect.right = position.x + new_frame_size.x;
1374 frame_rect.bottom = position.y + new_frame_size.y;
1378 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1379 position = wxPoint(10, 10);
1384 const wxPoint ptScreen(position.x, position.y);
1385 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1387 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1390 g_nframewin_posx = position.x;
1391 g_nframewin_posy = position.y;
1394 wxSize asz = getAndroidDisplayDimensions();
1399 if ((cw > 200) && (ch > 200))
1400 new_frame_size.Set(cw, ch);
1402 new_frame_size.Set(800, 400);
1406 long app_style = wxDEFAULT_FRAME_STYLE;
1407 app_style |= wxWANTS_CHARS;
1412 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1413 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1416 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1417 myframe_window_title += g_Platform->GetHomeDir();
1418 myframe_window_title +=
"]";
1422 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1423 new_frame_size.x, new_frame_size.y, position.x, position.y);
1427 auto dockart =
new wxAuiDefaultDockArt;
1430 gFrame =
new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1431 app_style, dockart);
1436 g_pauimgr->SetDockSizeConstraint(.9, .9);
1442 g_Platform->Initialize_3();
1444 gFrame->CreateCanvasLayout();
1448 gFrame->SetChartUpdatePeriod();
1452 gFrame->ApplyGlobalSettings(
false);
1453 gFrame->SetAllToolbarScale();
1454 gFrame->SetAndApplyColorScheme(global_color_scheme);
1455 if (g_bframemax) gFrame->Maximize(
true);
1458 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->
GetPixPerMM() > 4.0))
1459 gFrame->Maximize(
true);
1468 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1469 g_GLOptions.m_bTextureCompressionCaching) {
1470 gFrame->ReloadAllVP();
1489 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1490 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1493 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1494 wxLogMessage(dogmsg);
1496 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1504 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1509 gFrame->DoChartUpdate();
1512 auto style = g_StyleManager->GetCurrentStyle();
1513 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1515 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1517 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1527 wxString perspective;
1528 pConfig->SetPath(
"/AUI");
1529 pConfig->Read(
"AUIPerspective", &perspective);
1536 bool bno_load =
false;
1538 wxArrayString name_array;
1539 wxStringTokenizer st(perspective,
"|;");
1540 while (st.HasMoreTokens()) {
1541 wxString s1 = st.GetNextToken();
1542 if (s1.StartsWith(
"name=")) {
1543 wxString sc = s1.AfterFirst(
'=');
1548 wxAuiPaneInfoArray pane_array_val =
g_pauimgr->GetAllPanes();
1549 for (
unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1550 wxAuiPaneInfo pane = pane_array_val.Item(i);
1554 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1560 if (!bno_load)
g_pauimgr->LoadPerspective(perspective,
false);
1565 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1568 wxSize frameSize = GetClientSize();
1569 wxSize minSize =
g_pauimgr->GetPane(cc).min_size;
1570 int width = wxMax(minSize.x, frameSize.x / 10);
1571 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1593 if (!g_bdisable_opengl) {
1596 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1597 gFrame->m_defer_size = gFrame->GetSize();
1598 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1600 gFrame->m_bdefer_resize =
true;
1610 glDeleteTextures(n, texts);
1619 gFrame->SetSize(getAndroidDisplayDimensions());
1620 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0,
true);
1632void MyApp::LoadChartDatabase() {
1634 ArrayOfCDI ChartDirArray;
1635 pConfig->LoadChartDirArray(ChartDirArray);
1640 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1643 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1644 if (RegKey.Exists()) {
1646 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1648 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1650 wxStringTokenizer tkz(dirs,
";");
1651 while (tkz.HasMoreTokens()) {
1652 wxString token = tkz.GetNextToken();
1655 cdi.fullpath = token.Trim();
1656 cdi.magic_number =
"";
1658 ChartDirArray.Add(cdi);
1665 cdi.fullpath =
"charts";
1666 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1667 cdi.magic_number =
"";
1668 ChartDirArray.Add(cdi);
1672 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1682 if (!ChartDirArray.GetCount())
1683 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1693 if (g_restore_dbindex >= 0) {
1694 if (
ChartData->GetChartTableEntries() == 0)
1695 g_restore_dbindex = -1;
1697 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1698 g_restore_dbindex = 0;
1706 wxLogMessage(
"opencpn::MyApp starting exit.");
1708 m_usb_watcher.Stop();
1711 wxDateTime lognow = wxDateTime::Now();
1713 wxString day = lognow.FormatISODate();
1714 wxString utc = lognow.FormatISOTime();
1715 wxString navmsg =
"LOGBOOK: ";
1723 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ",
gLat,
gLon);
1727 if (std::isnan(
gCog))
1728 cog.Printf(
"COG ----- ");
1730 cog.Printf(
"COG %10.5f ",
gCog);
1733 if (std::isnan(
gSog))
1734 sog.Printf(
"SOG ----- ");
1736 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(
gSog));
1743 data.Printf(
"OFF: Lat %10.5f Lon %10.5f",
gLat,
gLon);
1746 wxLogMessage(navmsg);
1747 g_loglast_time = lognow;
1765 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1774 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1775 wxLog::FlushActive();
1777 g_Platform->CloseLogFile();
1779 delete pInit_Chart_Dir;
1787 delete pWayPointMan;
1789 navutil::DeinitGlobals();
1791 DeInitializeUserColors();
1798 delete g_StyleManager;
1803 void RestoreSystemColors();
1804 RestoreSystemColors();
1811#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1815 FontMgr::Shutdown();
1817 g_Platform->OnExit_2();
1824#ifdef LINUX_CRASHRPT
1825void MyApp::OnFatalException() { g_crashprint.Report(); }
1831void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1836 if (eErrClass == CE_Debug)
1837 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1838 else if (eErrClass == CE_Warning)
1839 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1841 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1843 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.
A modal message dialog with confirmation button and cancel button.
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.
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.