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"
119#include "model/nav_object_database.h"
131#include "ais_info_gui.h"
143#include "dialog_alert.h"
146#include "gdal/cpl_csv.h"
160#include "route_ctx_factory.h"
167#include "safe_mode_gui.h"
168#include "std_filesystem.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"
320wxString 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;
342 : wxFrame(
nullptr, wxID_ANY,
"Loading...", wxDefaultPosition,
343 wxSize(900, 600), wxSTAY_ON_TOP) {
345 SetBackgroundColour(wxColour(0, 0, 0));
349 new wxStaticText(
this, wxID_ANY,
"", wxDefaultPosition, wxDefaultSize,
350 wxALIGN_CENTRE_HORIZONTAL);
351 text->SetForegroundColour(wxColour(255, 255, 255));
353 wxBoxSizer *sizer =
new wxBoxSizer(wxVERTICAL);
354 sizer->Add(text, 1, wxALIGN_CENTER);
355 SetSizerAndFit(sizer);
361bool ShowNavWarning() {
364OpenCPN is distributed in the hope that it will be useful, \
365but WITHOUT ANY WARRANTY; without even the implied \
366warranty of MERCHANTABILITY or FITNESS FOR A \
367PARTICULAR PURPOSE.\n\n\
368See the GNU General Public License for more details.\n\n\
369OpenCPN must only be used in conjunction with approved \
370paper charts and traditional methods of navigation.\n\n\
371DO NOT rely upon OpenCPN for safety of life or property.\n\n\
372Please click \"Agree\" and proceed, or \"Cancel\" to quit.\n"));
374 wxString vs = wxString::Format(
" .. Version %s", VERSION_FULL);
377 androidShowDisclaimer(_(
"OpenCPN for Android") + vs, msg);
380 msg.Replace(
"\n",
"<br>");
382 std::stringstream html;
383 html <<
"<html><body><p>";
384 html << msg.ToStdString();
385 html <<
"</p></body></html>";
387 std::string title = _(
"Welcome to OpenCPN").ToStdString();
388 std::string action = _(
"Agree").ToStdString();
390 info_dlg.SetInitialSize();
391 info_dlg.AddHtmlContent(html);
392 int agreed = info_dlg.ShowModal();
393 return agreed == wxID_OK;
397bool DoNavMessage(wxString &new_version_string) {
402 if (!n_NavMessageShown || (new_version_string != g_config_version_string) ||
403 (g_AndroidVersionCode != androidGetVersionCode())) {
407 if (!ShowNavWarning()) {
408 qDebug() <<
"Closing due to NavWarning Cancel";
414 n_NavMessageShown = 1;
418 g_AndroidVersionCode = androidGetVersionCode();
419 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
424 if (!n_NavMessageShown || (new_version_string != g_config_version_string)) {
425 if (!ShowNavWarning())
return false;
426 n_NavMessageShown = 1;
439BEGIN_EVENT_TABLE(
MyApp, wxApp)
440EVT_ACTIVATE_APP(MyApp::OnActivateApp)
443static
void ActivateRoute(const std::
string &guid) {
446 wxLogMessage(
"Cannot activate guid: no such route");
457 point = route->GetPoint(2);
464static void ReverseRoute(
const std::string &guid) {
467 wxLogMessage(
"Cannot activate guid: no such route");
474void MyApp::InitRestListeners() {
475 auto activate_route = [&](wxCommandEvent ev) {
476 auto guid = ev.GetString().ToStdString();
480 auto reverse_route = [&](wxCommandEvent ev) {
481 auto guid = ev.GetString().ToStdString();
487bool MyApp::OpenFile(
const std::string &path) {
489 auto result = nav_objects.load_file(path.c_str());
491 std::string s(_(
"Cannot load route or waypoint file: "));
492 s += std::string(
"\"") + path +
"\"";
493 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
499 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
501 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
502 pRouteManagerDialog->UpdateLists();
503 LLBBox box = nav_objects.GetBBox();
504 if (box.GetValid()) {
505 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
511void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
514 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
515 parser.AddSwitch(
"p",
"portable");
516 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
517 wxCMD_LINE_PARAM_OPTIONAL);
518 parser.AddSwitch(
"f",
"fullscreen");
519 parser.AddSwitch(
"G",
"no_opengl");
520 parser.AddSwitch(
"W",
"config_wizard");
521 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
522 parser.AddSwitch(
"D",
"rebuild_chart_db");
523 parser.AddSwitch(
"P",
"parse_all_enc");
524 parser.AddOption(
"l",
"loglevel");
525 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
526 parser.AddSwitch(
"U",
"unit_test_2");
527 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
528 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
529 parser.AddSwitch(
"s",
"safe_mode");
530 parser.AddSwitch(
"r",
"remote");
531 parser.AddSwitch(
"R",
"raise");
532 parser.AddSwitch(
"q",
"quit");
533 parser.AddSwitch(
"e",
"get_rest_endpoint");
534 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
535 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
541static void ParseLoglevel(wxCmdLineParser &parser) {
542 wxLog::SetLogLevel(wxLOG_Message);
545static void ParseLoglevel(wxCmdLineParser &parser) {
546 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
547 strLevel = strLevel ? strLevel :
"info";
549 if (parser.Found(
"l", &wxLevel)) {
550 strLevel = wxLevel.c_str();
552 wxLogLevel level = OcpnLog::str2level(strLevel);
553 if (level == OcpnLog::LOG_BADLEVEL) {
554 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
557 wxLog::SetLogLevel(level);
562bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
569bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
574 g_unit_test_2 = parser.Found(
"unit_test_2");
575 g_bportable = parser.Found(
"p");
576 g_start_fullscreen = parser.Found(
"fullscreen");
577 g_bdisable_opengl = parser.Found(
"no_opengl");
578 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
580 g_parse_all_enc = parser.Found(
"parse_all_enc");
581 g_config_wizard = parser.Found(
"config_wizard");
582 if (parser.Found(
"unit_test_1", &number)) {
583 g_unit_test_1 =
static_cast<int>(number);
584 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
586 safe_mode::set_mode(parser.Found(
"safe_mode"));
587 ParseLoglevel(parser);
589 if (parser.Found(
"configdir", &wxstr)) {
590 g_configdir = wxstr.ToStdString();
591 fs::path path(g_configdir);
592 if (!fs::exists(path) || !fs::is_directory(path)) {
593 std::cerr << g_configdir <<
" is not an existing directory.\n";
598 bool has_start_options =
false;
599 static const std::vector<std::string> kStartOptions = {
604 "rebuild_gl_raster_cache",
610 for (
const auto &opt : kStartOptions) {
611 if (parser.Found(opt)) has_start_options =
true;
613 if (has_start_options && parser.Found(
"remote")) {
614 std::cerr <<
"this option is not compatible with --remote\n";
618 bool has_remote_options =
false;
619 static const std::vector<std::string> kRemoteOptions = {
620 "raise",
"quit",
"open",
"get_rest_endpoint"};
621 for (
const auto &opt : kRemoteOptions) {
622 if (parser.Found(opt)) has_remote_options =
true;
624 if (has_remote_options && !parser.Found(
"remote")) {
625 std::cerr <<
"This option requires --remote\n";
629 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
630 g_params.push_back(parser.GetParam(paramNr).ToStdString());
633 if (!parser.Found(
"remote"))
634 m_parsed_cmdline = ParsedCmdline();
635 else if (parser.Found(
"raise"))
636 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
637 else if (parser.Found(
"quit"))
638 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
639 else if (parser.Found(
"get_rest_endpoint"))
640 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
641 else if (parser.Found(
"open", &optarg))
642 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
643 else if (parser.GetParamCount() == 1)
645 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
646 else if (!has_start_options && !has_remote_options) {
648 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
658bool MyApp::OnExceptionInMainLoop() {
659 wxLogWarning(
"Caught MainLoopException, continuing...");
664void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
666static wxStopWatch init_sw;
669 if (m_exitcode != -2)
return m_exitcode;
670 return wxAppConsole::OnRun();
681 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
682 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
683 setenv(
"GDK_BACKEND",
"x11", 1);
687 "mesa_glthread",
"false",
696 if (!wxApp::OnInit())
return false;
699 androidEnableBackButton(
false);
700 androidEnableOptionItems(
false);
705#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
711 wxBitmap bmp(10, 10, -1);
713 dc.SelectObject(bmp);
714 dc.DrawText(
"X", 0, 0);
726 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
730 std::cerr <<
"No remote opencpn found. Giving up.\n";
735 std::unique_ptr<LocalClientApi> client;
737 client = LocalClientApi::GetClient();
739 WARNING_LOG <<
"Ipc client exception: " << ie.str();
746 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
747 "to respond.\nPlease retry."),
748 "OpenCPN", wxICON_INFORMATION | wxOK);
753 auto result = client->HandleCmdline(m_parsed_cmdline.action,
754 m_parsed_cmdline.arg);
758 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
767 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
768 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
773 if (!safe_mode::get_mode()) {
779 OCPNPlatform::Initialize_1();
784 MyApp::SetAppDisplayName(
"OpenCPN");
787 wxDateTime x = wxDateTime::UNow();
788 long seed = x.GetMillisecond();
789 seed *= x.GetTicks();
794 setlocale(LC_NUMERIC,
"C");
796 g_start_time = wxDateTime::Now();
798 g_loglast_time = g_start_time;
799 g_loglast_time.MakeGMT();
800 g_loglast_time.Subtract(
801 wxTimeSpan(0, 29, 0, 0));
803 AnchorPointMinDist = 5.0;
809 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
813 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
814 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
815 wxFONTENCODING_SYSTEM);
816 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
819 auto ¬eman = NotificationManager::GetInstance();
820 noteman.ScrubNotificationDirectory(30);
823 if (!g_Platform->InitializeLogFile()) {
835 wxLogMessage(
"\n\n________\n");
837 wxDateTime now = wxDateTime::Now();
838 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
839 now.FormatISODate().mb_str().data());
840 wxLogLevel level = wxLog::GetLogLevel();
841 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
843 wxString wxver(wxVERSION_STRING);
844 wxver.Prepend(
"wxWidgets version: ");
846 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
850 os_name = platforminfo.GetOperatingSystemIdName();
852 os_name = platforminfo.GetOperatingSystemFamilyName();
855 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
856 platforminfo.GetPortIdName();
858 wxLogMessage(wxver +
" " + platform);
860 ::wxGetOsVersion(&osMajor, &osMinor);
861 wxString osVersionMsg;
862 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
863 wxLogMessage(osVersionMsg);
865 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
866 g_mem_total / 1024, g_mem_initial / 1024);
871 if (!detail->osd_names_like.empty())
872 like0 = detail->osd_names_like[0].c_str();
873 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
874 detail->osd_arch.c_str(), detail->osd_name.c_str(),
875 detail->osd_version.c_str(), detail->osd_ID.c_str(),
877 wxLogMessage(msgplat);
879 wxString imsg =
"SData_Locn is ";
880 imsg += g_Platform->GetSharedDataDir();
884 ::wxInitAllImageHandlers();
888 prepareAndroidStyleSheets();
892 pInit_Chart_Dir =
new wxString();
897 imsg =
"PrivateDataDir is ";
903 navutil::InitGlobals();
907 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
911 pSelect->SetSelectPixelRadius(12);
924 g_pais_query_dialog_active = NULL;
927 g_hostname = ::wxGetHostName();
928 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
930 androidGetDeviceInfo();
931 g_hostname = wxString(
"Android-") + g_android_Device_Model;
932 g_hostname.Replace(
" ",
"-",
true);
937 wxString p(
"Portable-");
938 g_hostname = p + g_hostname;
943 pLayerList =
new LayerList;
948 auto &navobj_db = NavObj_dB::GetInstance();
955#ifdef PROBE_PORTS__WITH_HELPER
956 user_user_id = getuid();
957 file_user_id = geteuid();
961 bool b_initial_load =
false;
963 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
964 if (config_test_file_name.FileExists())
965 wxLogMessage(
"Using existing Config_File: " +
966 g_Platform->GetConfigFileName());
969 wxLogMessage(
"Creating new Config_File: " +
970 g_Platform->GetConfigFileName());
972 b_initial_load =
true;
975 config_test_file_name.DirExists(config_test_file_name.GetPath()))
976 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
977 wxLogMessage(
"Cannot create config file directory for " +
978 g_Platform->GetConfigFileName());
983 pConfig = g_Platform->GetConfigObject();
984 InitBaseConfig(pConfig);
985 pConfig->LoadMyConfig();
987 if (g_kiosk_startup) {
989 g_wallpaper->ShowFullScreen(
true);
995 if (b_initial_load) g_Platform->SetDefaultOptions();
997 g_Platform->applyExpertMode(g_bUIexpert);
1002 g_StyleManager->SetStyle(
"MUI_flat");
1003 if (!g_StyleManager->IsOK()) {
1004 wxString msg = _(
"Failed to initialize the user interface. ");
1005 msg << _(
"OpenCPN cannot start. ");
1006 msg << _(
"The necessary configuration files were not found. ");
1007 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
1008 << _(
" for details.") <<
"\n\n";
1009 msg << g_Platform->GetSharedDataDir();
1011 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
1012 wxCANCEL | wxICON_ERROR);
1019 if (style) style->chartStatusWindowTransparent =
true;
1023 pWayPointMan = NULL;
1027 msg.Printf(
"Detected display size (horizontal): %d mm",
1032 if (g_config_display_size_manual &&
1037 msg.Printf(
"Display size (horizontal) config override: %d mm",
1046 int SelectPixelRadius = 50;
1048 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1049 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1050 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1054 if (!n_NavMessageShown) {
1061#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1064 g_Platform->SetLocaleSearchPrefixes();
1066 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1068 imsg =
"System default Language: " + def_lang_canonical;
1071 wxString cflmsg =
"Config file language: " + g_locale;
1072 wxLogMessage(cflmsg);
1074 if (g_locale.IsEmpty()) {
1075 g_locale = def_lang_canonical;
1076 cflmsg =
"Config file language empty, using system default: " + g_locale;
1077 wxLogMessage(cflmsg);
1081 g_locale = g_Platform->GetAdjustedAppLocale();
1082 cflmsg =
"Adjusted App language: " + g_locale;
1083 wxLogMessage(cflmsg);
1086 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1088 imsg =
"Opencpn language set to: ";
1095 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1097 wxLogMessage(
"wxLocale support not available");
1102 if (g_config_wizard || b_initial_load) {
1104 auto res = wiz.Run();
1115 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1116 g_bUpgradeInProcess = (vs != g_config_version_string);
1118 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1121 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1122 wxLogMessage(g_Platform->GetLargeLogMessage());
1127 g_bdisable_opengl =
true;
1130 if (g_bdisable_opengl) g_bopengl =
false;
1132#if defined(__linux__) && !defined(__ANDROID__)
1133 if (g_bSoftwareGL) {
1134 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1147 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1149 wxMin(g_memCacheLimit, 1024 * 1024);
1155 g_memCacheLimit = 0;
1156 if (0 == g_nCacheLimit)
1157 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1162 "chartlist.dat",
"CHRTLIST.DAT");
1166 "mmsitoname.csv",
"MMSINAME.CSV");
1169 if (pInit_Chart_Dir->IsEmpty()) {
1170 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1174 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1176 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1180 InitRestListeners();
1183 gDefaultWorldMapLocation =
"gshhs";
1184 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1185 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1186 if (gWorldMapLocation == wxEmptyString) {
1187 gWorldMapLocation = gDefaultWorldMapLocation;
1192 wxString default_tcdata0 =
1193 (g_Platform->GetSharedDataDir() +
"tcdata" +
1194 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1195 wxString default_tcdata1 =
1196 (g_Platform->GetSharedDataDir() +
"tcdata" +
1197 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1199 if (TideCurrentDataSet.empty()) {
1200 TideCurrentDataSet.push_back(
1201 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1202 TideCurrentDataSet.push_back(
1203 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1208 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1209 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1210 wxFileName::GetPathSeparator() +
"2bells.wav");
1211 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1216 g_Platform->Initialize_2();
1218 LoadChartDatabase();
1222 g_kiosk_startup =
false;
1226 if (!g_kiosk_startup) {
1228 SetTopWindow(gFrame);
1233 gFrame->InitTimer.Start(50, wxTIMER_CONTINUOUS);
1239 OCPNPlatform::Initialize_4();
1242 androidHideBusyIcon();
1245 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1249 if (!g_kiosk_startup) {
1250 if (!DoNavMessage(vs)) {
1257 g_bHasHwClock =
true;
1258#if defined(__UNIX__) && !defined(__ANDROID__)
1261 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1262 (stat(
"/dev/misc/rtc", &buffer) == 0));
1265 g_config_version_string = vs;
1268 pConfig->UpdateSettings();
1270 for (
auto *cp : TheConnectionParams()) {
1272 if (cp->GetDSPort().Contains(
"Serial")) {
1273 std::string port(cp->Port.ToStdString());
1281 m_comm_bridge.Initialize();
1283 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1286 if (ipv4_addrs.size()) {
1287 std::string ipAddr = ipv4_addrs[0];
1290 if (data_dir.Last() != wxFileName::GetPathSeparator())
1291 data_dir.Append(wxFileName::GetPathSeparator());
1293 make_certificate(ipAddr, data_dir.ToStdString());
1295 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1296 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1307 g_wallpaper->Show(
false);
1310 gFrame->ShowFullScreen(
true);
1313 g_wallpaper->Destroy();
1314 g_wallpaper =
nullptr;
1316 SetTopWindow(gFrame);
1319 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1320 if (!DoNavMessage(vs)) {
1325 gFrame->InitTimer.Start(50, wxTIMER_CONTINUOUS);
1331 wxSize new_frame_size(-1, -1);
1333 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1335 InitializeUserColors();
1337 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1338 (g_nframewin_y <= ch))
1339 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1341 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1347 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1348 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1349 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1350 g_bframemax =
false;
1353 g_lastClientRectx = cx;
1354 g_lastClientRecty = cy;
1355 g_lastClientRectw = cw;
1356 g_lastClientRecth = ch;
1359 wxPoint position(0, 0);
1360 wxSize dsize = wxGetDisplaySize();
1363 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1366 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1367 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1372 frame_rect.left = position.x;
1373 frame_rect.top = position.y;
1374 frame_rect.right = position.x + new_frame_size.x;
1375 frame_rect.bottom = position.y + new_frame_size.y;
1379 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1380 position = wxPoint(10, 10);
1385 const wxPoint ptScreen(position.x, position.y);
1386 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1388 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1391 g_nframewin_posx = position.x;
1392 g_nframewin_posy = position.y;
1395 wxSize asz = getAndroidDisplayDimensions();
1400 if ((cw > 200) && (ch > 200))
1401 new_frame_size.Set(cw, ch);
1403 new_frame_size.Set(800, 400);
1407 long app_style = wxDEFAULT_FRAME_STYLE;
1408 app_style |= wxWANTS_CHARS;
1413 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1414 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1417 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1418 myframe_window_title += g_Platform->GetHomeDir();
1419 myframe_window_title +=
"]";
1423 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1424 new_frame_size.x, new_frame_size.y, position.x, position.y);
1428 auto dockart =
new wxAuiDefaultDockArt;
1431 gFrame =
new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1432 app_style, dockart);
1437 g_pauimgr->SetDockSizeConstraint(.9, .9);
1443 g_Platform->Initialize_3();
1445 gFrame->CreateCanvasLayout();
1449 gFrame->SetChartUpdatePeriod();
1453 gFrame->ApplyGlobalSettings(
false);
1454 gFrame->SetAllToolbarScale();
1455 gFrame->SetAndApplyColorScheme(global_color_scheme);
1456 if (g_bframemax) gFrame->Maximize(
true);
1459 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->
GetPixPerMM() > 4.0))
1460 gFrame->Maximize(
true);
1469 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1470 g_GLOptions.m_bTextureCompressionCaching) {
1471 gFrame->ReloadAllVP();
1490 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1491 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1494 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1495 wxLogMessage(dogmsg);
1497 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1505 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1510 gFrame->DoChartUpdate();
1513 for (
auto *cp : TheConnectionParams()) {
1516 cp->b_IsSetup = TRUE;
1522 auto style = g_StyleManager->GetCurrentStyle();
1523 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1525 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1527 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1537 wxString perspective;
1538 pConfig->SetPath(
"/AUI");
1539 pConfig->Read(
"AUIPerspective", &perspective);
1546 bool bno_load =
false;
1548 wxArrayString name_array;
1549 wxStringTokenizer st(perspective,
"|;");
1550 while (st.HasMoreTokens()) {
1551 wxString s1 = st.GetNextToken();
1552 if (s1.StartsWith(
"name=")) {
1553 wxString sc = s1.AfterFirst(
'=');
1558 wxAuiPaneInfoArray pane_array_val =
g_pauimgr->GetAllPanes();
1559 for (
unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1560 wxAuiPaneInfo pane = pane_array_val.Item(i);
1564 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1570 if (!bno_load)
g_pauimgr->LoadPerspective(perspective,
false);
1575 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1578 wxSize frameSize = GetClientSize();
1579 wxSize minSize =
g_pauimgr->GetPane(cc).min_size;
1580 int width = wxMax(minSize.x, frameSize.x / 10);
1581 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1603 if (!g_bdisable_opengl) {
1606 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1607 gFrame->m_defer_size = gFrame->GetSize();
1608 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1610 gFrame->m_bdefer_resize =
true;
1620 glDeleteTextures(n, texts);
1629 gFrame->SetSize(getAndroidDisplayDimensions());
1630 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0,
true);
1642void MyApp::LoadChartDatabase() {
1644 ArrayOfCDI ChartDirArray;
1645 pConfig->LoadChartDirArray(ChartDirArray);
1650 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1653 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1654 if (RegKey.Exists()) {
1656 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1658 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1660 wxStringTokenizer tkz(dirs,
";");
1661 while (tkz.HasMoreTokens()) {
1662 wxString token = tkz.GetNextToken();
1665 cdi.fullpath = token.Trim();
1666 cdi.magic_number =
"";
1668 ChartDirArray.Add(cdi);
1675 cdi.fullpath =
"charts";
1676 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1677 cdi.magic_number =
"";
1678 ChartDirArray.Add(cdi);
1682 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1692 if (!ChartDirArray.GetCount())
1693 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1703 if (g_restore_dbindex >= 0) {
1704 if (
ChartData->GetChartTableEntries() == 0)
1705 g_restore_dbindex = -1;
1707 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1708 g_restore_dbindex = 0;
1716 wxLogMessage(
"opencpn::MyApp starting exit.");
1718 m_usb_watcher.Stop();
1721 wxDateTime lognow = wxDateTime::Now();
1723 wxString day = lognow.FormatISODate();
1724 wxString utc = lognow.FormatISOTime();
1725 wxString navmsg =
"LOGBOOK: ";
1733 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ",
gLat,
gLon);
1737 if (std::isnan(
gCog))
1738 cog.Printf(
"COG ----- ");
1740 cog.Printf(
"COG %10.5f ",
gCog);
1743 if (std::isnan(
gSog))
1744 sog.Printf(
"SOG ----- ");
1746 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(
gSog));
1753 data.Printf(
"OFF: Lat %10.5f Lon %10.5f",
gLat,
gLon);
1756 wxLogMessage(navmsg);
1757 g_loglast_time = lognow;
1775 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1784 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1785 wxLog::FlushActive();
1787 g_Platform->CloseLogFile();
1789 delete pInit_Chart_Dir;
1797 delete pWayPointMan;
1799 navutil::DeinitGlobals();
1801 DeInitializeUserColors();
1808 delete g_StyleManager;
1813 void RestoreSystemColors();
1814 RestoreSystemColors();
1821#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1825 FontMgr::Shutdown();
1827 g_Platform->OnExit_2();
1834#ifdef LINUX_CRASHRPT
1835void MyApp::OnFatalException() { g_crashprint.Report(); }
1841void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1846 if (eErrClass == CE_Debug)
1847 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1848 else if (eErrClass == CE_Warning)
1849 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1851 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1853 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.
void MakeLoopbackDriver()
Create and register the loopback 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.
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.