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"
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"
173#include "user_colors.h"
186void RedirectIOToConsole();
198#include "androidUTIL.h"
203using namespace std::literals::chrono_literals;
205const char *
const kUsage =
208 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
209 opencpn --remote [-R] | -q] | -e] |-o <str>]
211Options for starting opencpn
213 -c, --configdir=<dirpath> Use alternative configuration directory.
214 -p, --portable Run in portable mode.
215 -f, --fullscreen Switch to full screen mode on start.
216 -G, --no_opengl Disable OpenGL video acceleration. This setting will
218 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
219 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
220 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
221 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
222 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
223 Zero or negative <num> specifies no limit.
225 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
226 -W, --config_wizard Start with initial configuration wizard
228Options manipulating already started opencpn
229 -r, --remote Execute commands on already running instance
230 -R, --raise Make running OpenCPN visible if hidden
231 -q, --quit Terminate already running opencpn
232 -e, --get_rest_endpoint Print rest server endpoint and exit.
233 -o, --open=<GPX file> Open file in running opencpn
236 GPX file GPX-formatted file with waypoints or routes.
240wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
241wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
243wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
244wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
245wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
246wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
247wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
248wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
249wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
250wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
251wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
261WX_DEFINE_OBJARRAY(ArrayOfCDI);
263static int user_user_id;
264static int file_user_id;
266static int g_mem_total, g_mem_initial;
268static unsigned int malloc_max;
270static int osMajor, osMinor;
272static bool g_bHasHwClock;
274#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
276wxLocale *plocale_def_lang = 0;
284extern sigjmp_buf env;
289DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
290 0x6b, 0xba, 0xe7, 0x22, 0xc0);
294static const long long lNaN = 0xfff8000000000000;
295#define NAN (*(double *)&lNaN)
299void appendOSDirSlash(wxString *pString);
301void InitializeUserColors();
302void DeInitializeUserColors();
303void SetSystemColors(ColorScheme cs);
305static bool LoadAllPlugIns(
bool load_enabled) {
306 g_Platform->ShowBusySpinner();
307 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
308 g_Platform->HideBusySpinner();
316#if defined(__WXGTK__) || defined(__WXQT__)
317#include "bitmaps/opencpn.xpm"
320static wxString newPrivateFileName(wxString,
const char *name,
321 [[maybe_unused]]
const char *windowsName) {
322 wxString fname = wxString::FromUTF8(name);
323 wxString filePathAndName;
326 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
327 filePathAndName.Append(wxFileName::GetPathSeparator());
330 wxString fwname = wxString::FromUTF8(windowsName);
331 filePathAndName.Append(fwname);
333 filePathAndName.Append(fname);
336 return filePathAndName;
339void MyApp::OnNewMsgTypes() {
340 for (
auto it : m_api_events_callbacks)
341 it.second(
HostApi122::EventType::kNewMessageType);
344void MyApp::RegisterApiEventCallback(
345 const std::string &plugin_name,
348 m_api_events_callbacks[plugin_name] = std::move(callback);
350 m_api_events_callbacks.erase(plugin_name);
356 : wxFrame(
nullptr, wxID_ANY,
"Loading...", wxDefaultPosition,
357 wxSize(2000, 2000), wxSTAY_ON_TOP) {
359 SetBackgroundColour(wxColour(0, 0, 0));
361 wxPanel *panel =
new wxPanel(
this, wxID_ANY);
364 panel->SetBackgroundColour(wxColour(0, 0, 0));
367 wxBoxSizer *sizer =
new wxBoxSizer(wxVERTICAL);
368 sizer->Add(panel, 1, wxEXPAND);
375bool ShowNavWarning() {
378OpenCPN is distributed in the hope that it will be useful, \
379but WITHOUT ANY WARRANTY; without even the implied \
380warranty of MERCHANTABILITY or FITNESS FOR A \
381PARTICULAR PURPOSE.\n\n\
382See the GNU General Public License for more details.\n\n\
383OpenCPN must only be used in conjunction with approved \
384paper charts and traditional methods of navigation.\n\n\
385DO NOT rely upon OpenCPN for safety of life or property.\n\n\
386Please click \"Agree\" and proceed, or \"Cancel\" to quit.\n"));
388 wxString vs = wxString::Format(
" .. Version %s", VERSION_FULL);
391 androidShowDisclaimer(_(
"OpenCPN for Android") + vs, msg);
394 msg.Replace(
"\n",
"<br>");
396 std::stringstream html;
397 html <<
"<html><body><p>";
398 html << msg.ToStdString();
399 html <<
"</p></body></html>";
401 std::string title = _(
"Welcome to OpenCPN").ToStdString();
402 std::string action = _(
"Agree").ToStdString();
404 info_dlg.SetInitialSize();
405 info_dlg.AddHtmlContent(html);
406 int agreed = info_dlg.ShowModal();
407 return agreed == wxID_OK;
411bool DoNavMessage(wxString &new_version_string) {
416 if (!n_NavMessageShown || (new_version_string != g_config_version_string) ||
417 (g_AndroidVersionCode != androidGetVersionCode())) {
421 if (!ShowNavWarning()) {
422 qDebug() <<
"Closing due to NavWarning Cancel";
428 n_NavMessageShown = 1;
432 g_AndroidVersionCode = androidGetVersionCode();
433 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
438 if (!n_NavMessageShown || (new_version_string != g_config_version_string)) {
439 if (!ShowNavWarning())
return false;
440 n_NavMessageShown = 1;
453BEGIN_EVENT_TABLE(
MyApp, wxApp)
454EVT_ACTIVATE_APP(MyApp::OnActivateApp)
457static
void ActivateRoute(const std::
string &guid) {
460 wxLogMessage(
"Cannot activate guid: no such route");
471 point = route->GetPoint(2);
478static void ReverseRoute(
const std::string &guid) {
481 wxLogMessage(
"Cannot activate guid: no such route");
488void MyApp::InitRestListeners() {
489 auto activate_route = [&](wxCommandEvent ev) {
490 auto guid = ev.GetString().ToStdString();
494 auto reverse_route = [&](wxCommandEvent ev) {
495 auto guid = ev.GetString().ToStdString();
501void MyApp::OnUnhandledException() {
508 }
catch (std::exception &e) {
510 what.Printf(
"standard exception with message \"%s\"", e.what());
512 what.Printf(
"standard exception of type \"%s\" with message \"%s\"",
513 typeid(e).name(), e.what());
516 what =
"unknown exception";
518 wxMessageOutputBest().Printf(
519 "Unhandled %s; terminating %s.\n", what,
520 wxIsMainThread() ?
"the application" :
"the thread in which it happened");
523bool MyApp::OpenFile(
const std::string &path) {
525 auto result = nav_objects.load_file(path.c_str());
527 std::string s(_(
"Cannot load route or waypoint file: "));
528 s += std::string(
"\"") + path +
"\"";
529 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
535 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
539 LLBBox box = nav_objects.GetBBox();
540 if (box.GetValid()) {
541 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
547void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
550 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
551 parser.AddSwitch(
"p",
"portable");
552 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
553 wxCMD_LINE_PARAM_OPTIONAL);
554 parser.AddSwitch(
"f",
"fullscreen");
555 parser.AddSwitch(
"G",
"no_opengl");
556 parser.AddSwitch(
"W",
"config_wizard");
557 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
558 parser.AddSwitch(
"D",
"rebuild_chart_db");
559 parser.AddSwitch(
"P",
"parse_all_enc");
560 parser.AddOption(
"l",
"loglevel");
561 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
562 parser.AddSwitch(
"U",
"unit_test_2");
563 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
564 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
565 parser.AddSwitch(
"s",
"safe_mode");
566 parser.AddSwitch(
"r",
"remote");
567 parser.AddSwitch(
"R",
"raise");
568 parser.AddSwitch(
"q",
"quit");
569 parser.AddSwitch(
"e",
"get_rest_endpoint");
570 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
571 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
577static void ParseLoglevel(wxCmdLineParser &parser) {
578 wxLog::SetLogLevel(wxLOG_Message);
581static void ParseLoglevel(wxCmdLineParser &parser) {
582 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
583 strLevel = strLevel ? strLevel :
"info";
585 if (parser.Found(
"l", &wxLevel)) {
586 strLevel = wxLevel.c_str();
588 wxLogLevel level = OcpnLog::str2level(strLevel);
589 if (level == OcpnLog::LOG_BADLEVEL) {
590 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
593 wxLog::SetLogLevel(level);
598bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
605bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
610 g_unit_test_2 = parser.Found(
"unit_test_2");
611 g_bportable = parser.Found(
"p");
612 g_start_fullscreen = parser.Found(
"fullscreen");
613 g_bdisable_opengl = parser.Found(
"no_opengl");
614 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
616 g_parse_all_enc = parser.Found(
"parse_all_enc");
617 g_config_wizard = parser.Found(
"config_wizard");
618 if (parser.Found(
"unit_test_1", &number)) {
619 g_unit_test_1 =
static_cast<int>(number);
620 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
622 safe_mode::set_mode(parser.Found(
"safe_mode"));
623 ParseLoglevel(parser);
625 if (parser.Found(
"configdir", &wxstr)) {
626 g_configdir = wxstr.ToStdString();
627 fs::path path(g_configdir);
628 if (!fs::exists(path) || !fs::is_directory(path)) {
629 std::cerr << g_configdir <<
" is not an existing directory.\n";
634 bool has_start_options =
false;
635 static const std::vector<std::string> kStartOptions = {
640 "rebuild_gl_raster_cache",
646 for (
const auto &opt : kStartOptions) {
647 if (parser.Found(opt)) has_start_options =
true;
649 if (has_start_options && parser.Found(
"remote")) {
650 std::cerr <<
"this option is not compatible with --remote\n";
654 bool has_remote_options =
false;
655 static const std::vector<std::string> kRemoteOptions = {
656 "raise",
"quit",
"open",
"get_rest_endpoint"};
657 for (
const auto &opt : kRemoteOptions) {
658 if (parser.Found(opt)) has_remote_options =
true;
660 if (has_remote_options && !parser.Found(
"remote")) {
661 std::cerr <<
"This option requires --remote\n";
665 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
666 g_params.push_back(parser.GetParam(paramNr).ToStdString());
669 if (!parser.Found(
"remote"))
670 m_parsed_cmdline = ParsedCmdline();
671 else if (parser.Found(
"raise"))
672 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
673 else if (parser.Found(
"quit"))
674 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
675 else if (parser.Found(
"get_rest_endpoint"))
676 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
677 else if (parser.Found(
"open", &optarg))
678 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
679 else if (parser.GetParamCount() == 1)
681 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
682 else if (!has_start_options && !has_remote_options) {
684 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
694bool MyApp::OnExceptionInMainLoop() {
695 wxLogWarning(
"Caught MainLoopException, continuing...");
700void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
702static wxStopWatch init_sw;
705 if (m_exitcode != -2)
return m_exitcode;
706 return wxAppConsole::OnRun();
717 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
718 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
719 setenv(
"GDK_BACKEND",
"x11", 1);
723 "mesa_glthread",
"false",
732 if (!wxApp::OnInit())
return false;
735 androidEnableBackButton(
false);
736 androidEnableOptionItems(
false);
741#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
747 wxBitmap bmp(10, 10, -1);
749 dc.SelectObject(bmp);
750 dc.DrawText(
"X", 0, 0);
765 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
769 std::cerr <<
"No remote opencpn found. Giving up.\n";
774 std::unique_ptr<LocalClientApi> client;
776 client = LocalClientApi::GetClient();
778 WARNING_LOG <<
"Ipc client exception: " << ie.str();
785 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
786 "to respond.\nPlease retry."),
787 "OpenCPN", wxICON_INFORMATION | wxOK);
792 auto result = client->HandleCmdline(m_parsed_cmdline.action,
793 m_parsed_cmdline.arg);
797 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
806 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
807 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
812 if (!safe_mode::get_mode()) {
818 OCPNPlatform::Initialize_1();
823 MyApp::SetAppDisplayName(
"OpenCPN");
826 wxDateTime x = wxDateTime::UNow();
827 long seed = x.GetMillisecond();
828 seed *= x.GetTicks();
833 setlocale(LC_NUMERIC,
"C");
835 g_start_time = wxDateTime::Now();
837 g_loglast_time = g_start_time;
838 g_loglast_time.MakeGMT();
839 g_loglast_time.Subtract(
840 wxTimeSpan(0, 29, 0, 0));
842 AnchorPointMinDist = 5.0;
848 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
852 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
853 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
854 wxFONTENCODING_SYSTEM);
855 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
858 auto ¬eman = NotificationManager::GetInstance();
859 noteman.ScrubNotificationDirectory(30);
862 if (!g_Platform->InitializeLogFile()) {
874 wxLogMessage(
"\n\n________\n");
876 wxDateTime now = wxDateTime::Now();
877 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
878 now.FormatISODate().mb_str().data());
879 wxLogLevel level = wxLog::GetLogLevel();
880 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
882 wxString wxver(wxVERSION_STRING);
883 wxver.Prepend(
"wxWidgets version: ");
885 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
889 os_name = platforminfo.GetOperatingSystemIdName();
891 os_name = platforminfo.GetOperatingSystemFamilyName();
894 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
895 platforminfo.GetPortIdName();
897 wxLogMessage(wxver +
" " + platform);
899 ::wxGetOsVersion(&osMajor, &osMinor);
900 wxString osVersionMsg;
901 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
902 wxLogMessage(osVersionMsg);
904 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
905 g_mem_total / 1024, g_mem_initial / 1024);
910 if (!detail->osd_names_like.empty())
911 like0 = detail->osd_names_like[0].c_str();
912 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
913 detail->osd_arch.c_str(), detail->osd_name.c_str(),
914 detail->osd_version.c_str(), detail->osd_ID.c_str(),
916 wxLogMessage(msgplat);
918 wxString imsg =
"SData_Locn is ";
919 imsg += g_Platform->GetSharedDataDir();
923 ::wxInitAllImageHandlers();
927 prepareAndroidStyleSheets();
931 pInit_Chart_Dir =
new wxString();
936 imsg =
"PrivateDataDir is ";
942 navutil::InitGlobals();
946 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
950 pSelect->SetSelectPixelRadius(12);
963 g_pais_query_dialog_active = NULL;
966 g_hostname = ::wxGetHostName();
967 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
969 androidGetDeviceInfo();
970 g_hostname = wxString(
"Android-") + g_android_Device_Model;
971 g_hostname.Replace(
" ",
"-",
true);
976 wxString p(
"Portable-");
977 g_hostname = p + g_hostname;
982 pLayerList =
new LayerList;
987 auto &navobj_db = NavObj_dB::GetInstance();
994#ifdef PROBE_PORTS__WITH_HELPER
995 user_user_id = getuid();
996 file_user_id = geteuid();
1000 bool b_initial_load =
false;
1002 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
1003 if (config_test_file_name.FileExists())
1004 wxLogMessage(
"Using existing Config_File: " +
1005 g_Platform->GetConfigFileName());
1008 wxLogMessage(
"Creating new Config_File: " +
1009 g_Platform->GetConfigFileName());
1011 b_initial_load =
true;
1014 config_test_file_name.DirExists(config_test_file_name.GetPath()))
1015 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
1016 wxLogMessage(
"Cannot create config file directory for " +
1017 g_Platform->GetConfigFileName());
1022 pConfig = g_Platform->GetConfigObject();
1026 if (g_kiosk_startup) {
1028 g_wallpaper->Show();
1033 if (b_initial_load) g_Platform->SetDefaultOptions();
1035 g_Platform->applyExpertMode(g_bUIexpert);
1040 g_StyleManager->SetStyle(
"MUI_flat");
1041 if (!g_StyleManager->IsOK()) {
1042 wxString msg = _(
"Failed to initialize the user interface. ");
1043 msg << _(
"OpenCPN cannot start. ");
1044 msg << _(
"The necessary configuration files were not found. ");
1045 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
1046 << _(
" for details.") <<
"\n\n";
1047 msg << g_Platform->GetSharedDataDir();
1049 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
1050 wxCANCEL | wxICON_ERROR);
1057 if (style) style->chartStatusWindowTransparent =
true;
1061 pWayPointMan = NULL;
1065 msg.Printf(
"Detected display size (horizontal): %d mm",
1070 if (g_config_display_size_manual &&
1075 msg.Printf(
"Display size (horizontal) config override: %d mm",
1084 int SelectPixelRadius = 50;
1086 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1087 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1088 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1092 if (!n_NavMessageShown) {
1099#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1102 g_Platform->SetLocaleSearchPrefixes();
1104 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1106 imsg =
"System default Language: " + def_lang_canonical;
1109 wxString cflmsg =
"Config file language: " + g_locale;
1110 wxLogMessage(cflmsg);
1112 if (g_locale.IsEmpty()) {
1113 g_locale = def_lang_canonical;
1114 cflmsg =
"Config file language empty, using system default: " + g_locale;
1115 wxLogMessage(cflmsg);
1119 g_locale = g_Platform->GetAdjustedAppLocale();
1120 cflmsg =
"Adjusted App language: " + g_locale;
1121 wxLogMessage(cflmsg);
1124 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1126 imsg =
"Opencpn language set to: ";
1133 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1135 wxLogMessage(
"wxLocale support not available");
1140 if (g_config_wizard || b_initial_load) {
1142 auto res = wiz.Run();
1153 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1154 g_bUpgradeInProcess = (vs != g_config_version_string);
1156 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1159 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1160 wxLogMessage(g_Platform->GetLargeLogMessage());
1165 g_bdisable_opengl =
true;
1168 if (g_bdisable_opengl) g_bopengl =
false;
1170#if defined(__linux__) && !defined(__ANDROID__)
1171 if (g_bSoftwareGL) {
1172 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1185 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1187 wxMin(g_memCacheLimit, 1024 * 1024);
1193 g_memCacheLimit = 0;
1194 if (0 == g_nCacheLimit)
1195 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1200 "chartlist.dat",
"CHRTLIST.DAT");
1204 "mmsitoname.csv",
"MMSINAME.CSV");
1207 if (pInit_Chart_Dir->IsEmpty()) {
1208 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1212 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1214 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1218 InitRestListeners();
1219 new_msg_type_listener.
Init(NavMsgBus::GetInstance().new_msg_event,
1223 gDefaultWorldMapLocation =
"gshhs";
1224 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1225 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1226 if (gWorldMapLocation == wxEmptyString) {
1227 gWorldMapLocation = gDefaultWorldMapLocation;
1232 wxString default_tcdata0 =
1233 (g_Platform->GetSharedDataDir() +
"tcdata" +
1234 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1235 wxString default_tcdata1 =
1236 (g_Platform->GetSharedDataDir() +
"tcdata" +
1237 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1238 wxString default_tcdata2 =
1239 (g_Platform->GetSharedDataDir() +
"tcdata" +
1240 wxFileName::GetPathSeparator() +
"ticon-europe-global.tcd");
1242 if (TideCurrentDataSet.empty()) {
1243 TideCurrentDataSet.push_back(
1244 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1245 TideCurrentDataSet.push_back(
1246 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1247 TideCurrentDataSet.push_back(
1248 g_Platform->NormalizePath(default_tcdata2).ToStdString());
1253 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1254 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1255 wxFileName::GetPathSeparator() +
"2bells.wav");
1256 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1261 g_Platform->Initialize_2();
1263 LoadChartDatabase();
1267 g_kiosk_startup =
false;
1271 if (!g_kiosk_startup) {
1273 SetTopWindow(gFrame);
1280 OCPNPlatform::Initialize_4();
1283 androidHideBusyIcon();
1286 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1290 if (!g_kiosk_startup) {
1291 if (!DoNavMessage(vs)) {
1298 g_bHasHwClock =
true;
1299#if defined(__UNIX__) && !defined(__ANDROID__)
1302 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1303 (stat(
"/dev/misc/rtc", &buffer) == 0));
1306 g_config_version_string = vs;
1311 for (
auto *cp : TheConnectionParams()) {
1313 if (cp->GetDSPort().Contains(
"Serial")) {
1314 std::string port(cp->Port.ToStdString());
1321 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1324 if (ipv4_addrs.size()) {
1325 std::string ipAddr = ipv4_addrs[0];
1328 if (data_dir.Last() != wxFileName::GetPathSeparator())
1329 data_dir.Append(wxFileName::GetPathSeparator());
1331 make_certificate(ipAddr, data_dir.ToStdString());
1333 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1334 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1338 if (!g_kiosk_startup) {
1342 wxLogMessage(
"InitTimer start");
1343 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1353 CallAfter([
this]() {
1355 g_wallpaper->Show(
false);
1357 g_bFullscreen =
true;
1360 g_wallpaper->Destroy();
1361 g_wallpaper =
nullptr;
1363 SetTopWindow(gFrame);
1367 wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1368 if (!DoNavMessage(vs)) {
1374 wxLogMessage(
"InitTimer start");
1375 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1380void MyApp::BuildMainFrame() {
1383 wxSize new_frame_size(-1, -1);
1385 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1387 user_colors::Initialize();
1389 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1390 (g_nframewin_y <= ch))
1391 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1393 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1399 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1400 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1401 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1402 g_bframemax =
false;
1405 g_lastClientRectx = cx;
1406 g_lastClientRecty = cy;
1407 g_lastClientRectw = cw;
1408 g_lastClientRecth = ch;
1411 wxPoint position(0, 0);
1412 wxSize dsize = wxGetDisplaySize();
1415 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1418 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1419 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1424 frame_rect.left = position.x;
1425 frame_rect.top = position.y;
1426 frame_rect.right = position.x + new_frame_size.x;
1427 frame_rect.bottom = position.y + new_frame_size.y;
1431 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1432 position = wxPoint(10, 10);
1437 const wxPoint ptScreen(position.x, position.y);
1438 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1440 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1443 g_nframewin_posx = position.x;
1444 g_nframewin_posy = position.y;
1447 wxSize asz = getAndroidDisplayDimensions();
1452 if ((cw > 200) && (ch > 200))
1453 new_frame_size.Set(cw, ch);
1455 new_frame_size.Set(800, 400);
1461 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1462 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1465 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1466 myframe_window_title += g_Platform->GetHomeDir();
1467 myframe_window_title +=
"]";
1471 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1472 new_frame_size.x, new_frame_size.y, position.x, position.y);
1476 auto dockart =
new wxAuiDefaultDockArt;
1479 gFrame =
new MyFrame(myframe_window_title, position, new_frame_size,
1480 m_rest_server, dockart,
1481 [&](
const std::string &path) {
return OpenFile(path); });
1486 g_pauimgr->SetDockSizeConstraint(.9, .9);
1492 g_Platform->Initialize_3();
1494 gFrame->CreateCanvasLayout();
1496 gFrame->SetGPSCompassScale();
1500 gFrame->SetChartUpdatePeriod();
1504 gFrame->ApplyGlobalSettings(
false);
1505 gFrame->SetAllToolbarScale();
1506 gFrame->SetAndApplyColorScheme(global_color_scheme);
1507 if (g_bframemax) gFrame->Maximize(
true);
1510 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->
GetPixPerMM() > 4.0))
1511 gFrame->Maximize(
true);
1520 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1521 g_GLOptions.m_bTextureCompressionCaching) {
1522 gFrame->ReloadAllVP();
1541 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1545 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1546 wxLogMessage(dogmsg);
1548 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1556 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1561 gFrame->DoChartUpdate();
1563 CommBridge::GetInstance();
1566 for (
auto *cp : TheConnectionParams()) {
1569 cp->b_IsSetup = TRUE;
1576 auto style = g_StyleManager->GetCurrentStyle();
1577 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1579 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1581 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1583 AbstractPlatform::ShowBusySpinner();
1585 AbstractPlatform::HideBusySpinner();
1589 wxString perspective;
1591 pConfig->Read(
"AUIPerspective", &perspective);
1598 bool bno_load =
false;
1600 wxArrayString name_array;
1601 wxStringTokenizer st(perspective,
"|;");
1602 while (st.HasMoreTokens()) {
1603 wxString s1 = st.GetNextToken();
1604 if (s1.StartsWith(
"name=")) {
1605 wxString sc = s1.AfterFirst(
'=');
1610 wxAuiPaneInfoArray pane_array_val =
g_pauimgr->GetAllPanes();
1611 for (
unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1612 wxAuiPaneInfo pane = pane_array_val.Item(i);
1616 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1622 if (!bno_load)
g_pauimgr->LoadPerspective(perspective,
false);
1627 for (
unsigned int i = 0; i <
g_canvasArray.GetCount(); i++) {
1630 wxSize frameSize = GetClientSize();
1631 wxSize minSize =
g_pauimgr->GetPane(cc).min_size;
1632 int width = wxMax(minSize.x, frameSize.x / 10);
1633 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1655 if (!g_bdisable_opengl) {
1658 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1659 gFrame->m_defer_size = gFrame->GetSize();
1660 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1662 gFrame->m_bdefer_resize =
true;
1672 glDeleteTextures(n, texts);
1681 gFrame->SetSize(getAndroidDisplayDimensions());
1682 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1694void MyApp::LoadChartDatabase() {
1696 ArrayOfCDI ChartDirArray;
1697 pConfig->LoadChartDirArray(ChartDirArray);
1702 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1705 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1706 if (RegKey.Exists()) {
1708 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1710 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1712 wxStringTokenizer tkz(dirs,
";");
1713 while (tkz.HasMoreTokens()) {
1714 wxString token = tkz.GetNextToken();
1717 cdi.fullpath = token.Trim();
1718 cdi.magic_number =
"";
1720 ChartDirArray.Add(cdi);
1727 cdi.fullpath =
"charts";
1728 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1729 cdi.magic_number =
"";
1730 ChartDirArray.Add(cdi);
1734 if (ndirs)
pConfig->UpdateChartDirs(ChartDirArray);
1744 if (!ChartDirArray.GetCount())
1745 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1752 g_restore_dbindex = 0;
1756 if (g_restore_dbindex >= 0) {
1757 if (
ChartData->GetChartTableEntries() == 0)
1758 g_restore_dbindex = -1;
1760 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1761 g_restore_dbindex = 0;
1769 wxLogMessage(
"opencpn::MyApp starting exit.");
1771 m_usb_watcher.Stop();
1774 wxDateTime lognow = wxDateTime::Now();
1776 wxString day = lognow.FormatISODate();
1777 wxString utc = lognow.FormatISOTime();
1778 wxString navmsg =
"LOGBOOK: ";
1786 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ",
gLat,
gLon);
1790 if (std::isnan(
gCog))
1791 cog.Printf(
"COG ----- ");
1793 cog.Printf(
"COG %10.5f ",
gCog);
1796 if (std::isnan(
gSog))
1797 sog.Printf(
"SOG ----- ");
1799 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(
gSog));
1806 data.Printf(
"OFF: Lat %10.5f Lon %10.5f",
gLat,
gLon);
1809 wxLogMessage(navmsg);
1810 g_loglast_time = lognow;
1828 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1837 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1838 wxLog::FlushActive();
1840 g_Platform->CloseLogFile();
1842 delete pInit_Chart_Dir;
1850 delete pWayPointMan;
1852 navutil::DeinitGlobals();
1854 user_colors::DeInitialize();
1861 delete g_StyleManager;
1866 void RestoreSystemColors();
1867 RestoreSystemColors();
1874#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1878 FontMgr::Shutdown();
1880 g_Platform->OnExit_2();
1887#ifdef LINUX_CRASHRPT
1888void MyApp::OnFatalException() { g_crashprint.Report(); }
1894void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1899 if (eErrClass == CE_Debug)
1900 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1901 else if (eErrClass == CE_Warning)
1902 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1904 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1906 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.
arrayofCanvasPtr g_canvasArray
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().
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
Unstable development API.
EventType
Reported events bitmask.
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.
Custom event class for OpenCPN's notification system.
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.
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.
void MakeLoopbackDriver()
Create and register the loopback driver.
void MakeInternalDriver()
Create and register the internal driver.
void MakeCommDriver(const ConnectionParams *params)
Create and register a driver for given connection.
Communication drivers factory and support.
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.
Misc GUI event vars, a singleton.
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.
MyConfig * pConfig
Global instance.
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.
RouteManagerDialog * pRouteManagerDialog
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.