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>
114#include "model/nav_object_database.h"
126#include "ais_info_gui.h"
140#include "gdal/cpl_csv.h"
154#include "route_ctx_factory.h"
161#include "safe_mode_gui.h"
162#include "SoundFactory.h"
163#include "std_filesystem.h"
181void RedirectIOToConsole();
193#include "androidUTIL.h"
198using namespace std::literals::chrono_literals;
200const char *
const kUsage =
203 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
204 opencpn --remote [-R] | -q] | -e] |-o <str>]
206Options for starting opencpn
208 -c, --configdir=<dirpath> Use alternative configuration directory.
209 -p, --portable Run in portable mode.
210 -f, --fullscreen Switch to full screen mode on start.
211 -G, --no_opengl Disable OpenGL video acceleration. This setting will
213 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
214 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
215 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
216 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
217 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
218 Zero or negative <num> specifies no limit.
220 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
221 -W, --config_wizard Start with initial configuration wizard
223Options manipulating already started opencpn
224 -r, --remote Execute commands on already running instance
225 -R, --raise Make running OpenCPN visible if hidden
226 -q, --quit Terminate already running opencpn
227 -e, --get_rest_endpoint Print rest server endpoint and exit.
228 -o, --open=<GPX file> Open file in running opencpn
231 GPX file GPX-formatted file with waypoints or routes.
235wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
236wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
238wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
239wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
240wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
241wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
242wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
243wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
244wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
245wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
246wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
256WX_DEFINE_OBJARRAY(ArrayOfCDI);
258static int user_user_id;
259static int file_user_id;
261static int g_mem_total, g_mem_initial;
263static unsigned int malloc_max;
265static int osMajor, osMinor;
267static bool g_bHasHwClock;
269#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
271wxLocale *plocale_def_lang = 0;
279extern sigjmp_buf env;
284DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
285 0x6b, 0xba, 0xe7, 0x22, 0xc0);
289static const long long lNaN = 0xfff8000000000000;
290#define NAN (*(double *)&lNaN)
294void appendOSDirSlash(wxString *pString);
296void InitializeUserColors();
297void DeInitializeUserColors();
298void SetSystemColors(ColorScheme cs);
300static bool LoadAllPlugIns(
bool load_enabled) {
301 g_Platform->ShowBusySpinner();
302 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
303 g_Platform->HideBusySpinner();
311#if defined(__WXGTK__) || defined(__WXQT__)
312#include "bitmaps/opencpn.xpm"
315wxString newPrivateFileName(wxString,
const char *name,
316 [[maybe_unused]]
const char *windowsName) {
317 wxString fname = wxString::FromUTF8(name);
318 wxString filePathAndName;
321 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
322 filePathAndName.Append(wxFileName::GetPathSeparator());
325 wxString fwname = wxString::FromUTF8(windowsName);
326 filePathAndName.Append(fwname);
328 filePathAndName.Append(fname);
331 return filePathAndName;
340BEGIN_EVENT_TABLE(
MyApp, wxApp)
341EVT_ACTIVATE_APP(MyApp::OnActivateApp)
344static
void ActivateRoute(const std::
string &guid) {
347 wxLogMessage(
"Cannot activate guid: no such route");
358 point = route->GetPoint(2);
365static void ReverseRoute(
const std::string &guid) {
368 wxLogMessage(
"Cannot activate guid: no such route");
375void MyApp::InitRestListeners() {
376 auto activate_route = [&](wxCommandEvent ev) {
377 auto guid = ev.GetString().ToStdString();
381 auto reverse_route = [&](wxCommandEvent ev) {
382 auto guid = ev.GetString().ToStdString();
388bool MyApp::OpenFile(
const std::string &path) {
390 auto result = nav_objects.load_file(path.c_str());
392 std::string s(_(
"Cannot load route or waypoint file: "));
393 s += std::string(
"\"") + path +
"\"";
394 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
400 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
402 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
403 pRouteManagerDialog->UpdateLists();
404 LLBBox box = nav_objects.GetBBox();
405 if (box.GetValid()) {
406 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
412void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
415 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
416 parser.AddSwitch(
"p",
"portable");
417 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
418 wxCMD_LINE_PARAM_OPTIONAL);
419 parser.AddSwitch(
"f",
"fullscreen");
420 parser.AddSwitch(
"G",
"no_opengl");
421 parser.AddSwitch(
"W",
"config_wizard");
422 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
423 parser.AddSwitch(
"D",
"rebuild_chart_db");
424 parser.AddSwitch(
"P",
"parse_all_enc");
425 parser.AddOption(
"l",
"loglevel");
426 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
427 parser.AddSwitch(
"U",
"unit_test_2");
428 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
429 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
430 parser.AddSwitch(
"s",
"safe_mode");
431 parser.AddSwitch(
"r",
"remote");
432 parser.AddSwitch(
"R",
"raise");
433 parser.AddSwitch(
"q",
"quit");
434 parser.AddSwitch(
"e",
"get_rest_endpoint");
435 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
436 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
442static void ParseLoglevel(wxCmdLineParser &parser) {
443 wxLog::SetLogLevel(wxLOG_Message);
446static void ParseLoglevel(wxCmdLineParser &parser) {
447 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
448 strLevel = strLevel ? strLevel :
"info";
450 if (parser.Found(
"l", &wxLevel)) {
451 strLevel = wxLevel.c_str();
453 wxLogLevel level = OcpnLog::str2level(strLevel);
454 if (level == OcpnLog::LOG_BADLEVEL) {
455 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
458 wxLog::SetLogLevel(level);
463bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
470bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
475 g_unit_test_2 = parser.Found(
"unit_test_2");
476 g_bportable = parser.Found(
"p");
477 g_start_fullscreen = parser.Found(
"fullscreen");
478 g_bdisable_opengl = parser.Found(
"no_opengl");
479 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
481 g_parse_all_enc = parser.Found(
"parse_all_enc");
482 g_config_wizard = parser.Found(
"config_wizard");
483 if (parser.Found(
"unit_test_1", &number)) {
484 g_unit_test_1 =
static_cast<int>(number);
485 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
487 safe_mode::set_mode(parser.Found(
"safe_mode"));
488 ParseLoglevel(parser);
490 if (parser.Found(
"configdir", &wxstr)) {
491 g_configdir = wxstr.ToStdString();
492 fs::path path(g_configdir);
493 if (!fs::exists(path) || !fs::is_directory(path)) {
494 std::cerr << g_configdir <<
" is not an existing directory.\n";
499 bool has_start_options =
false;
500 static const std::vector<std::string> kStartOptions = {
505 "rebuild_gl_raster_cache",
511 for (
const auto &opt : kStartOptions) {
512 if (parser.Found(opt)) has_start_options =
true;
514 if (has_start_options && parser.Found(
"remote")) {
515 std::cerr <<
"this option is not compatible with --remote\n";
519 bool has_remote_options =
false;
520 static const std::vector<std::string> kRemoteOptions = {
521 "raise",
"quit",
"open",
"get_rest_endpoint"};
522 for (
const auto &opt : kRemoteOptions) {
523 if (parser.Found(opt)) has_remote_options =
true;
525 if (has_remote_options && !parser.Found(
"remote")) {
526 std::cerr <<
"This option requires --remote\n";
530 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
531 g_params.push_back(parser.GetParam(paramNr).ToStdString());
534 if (!parser.Found(
"remote"))
535 m_parsed_cmdline = ParsedCmdline();
536 else if (parser.Found(
"raise"))
537 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
538 else if (parser.Found(
"quit"))
539 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
540 else if (parser.Found(
"get_rest_endpoint"))
541 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
542 else if (parser.Found(
"open", &optarg))
543 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
544 else if (parser.GetParamCount() == 1)
546 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
547 else if (!has_start_options && !has_remote_options) {
549 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
559bool MyApp::OnExceptionInMainLoop() {
560 wxLogWarning(
"Caught MainLoopException, continuing...");
565void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
567static wxStopWatch init_sw;
570 if (m_exitcode != -2)
return m_exitcode;
571 return wxAppConsole::OnRun();
582 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
583 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
584 setenv(
"GDK_BACKEND",
"x11", 1);
588 "mesa_glthread",
"false",
594bool MyApp::OnInit() {
595 if (!wxApp::OnInit())
return false;
597 androidEnableBackButton(
false);
598 androidEnableOptionItems(
false);
603#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
609 wxBitmap bmp(10, 10, -1);
611 dc.SelectObject(bmp);
612 dc.DrawText(
"X", 0, 0);
624 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
628 std::cerr <<
"No remote opencpn found. Giving up.\n";
633 std::unique_ptr<LocalClientApi> client;
635 client = LocalClientApi::GetClient();
637 WARNING_LOG <<
"Ipc client exception: " << ie.str();
644 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
645 "to respond.\nPlease retry."),
646 "OpenCPN", wxICON_INFORMATION | wxOK);
651 auto result = client->HandleCmdline(m_parsed_cmdline.action,
652 m_parsed_cmdline.arg);
656 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
665 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
666 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
671 if (!safe_mode::get_mode()) {
677 OCPNPlatform::Initialize_1();
682 MyApp::SetAppDisplayName(
"OpenCPN");
685 wxDateTime x = wxDateTime::UNow();
686 long seed = x.GetMillisecond();
687 seed *= x.GetTicks();
692 setlocale(LC_NUMERIC,
"C");
694 g_start_time = wxDateTime::Now();
696 g_loglast_time = g_start_time;
697 g_loglast_time.MakeGMT();
698 g_loglast_time.Subtract(
699 wxTimeSpan(0, 29, 0, 0));
701 AnchorPointMinDist = 5.0;
711 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
712 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
713 wxFONTENCODING_SYSTEM);
714 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
717 auto ¬eman = NotificationManager::GetInstance();
718 noteman.ScrubNotificationDirectory(30);
721 if (!g_Platform->InitializeLogFile()) {
733 wxLogMessage(
"\n\n________\n");
735 wxDateTime now = wxDateTime::Now();
736 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
737 now.FormatISODate().mb_str().data());
738 wxLogLevel level = wxLog::GetLogLevel();
739 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
741 wxString wxver(wxVERSION_STRING);
742 wxver.Prepend(
"wxWidgets version: ");
744 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
748 os_name = platforminfo.GetOperatingSystemIdName();
750 os_name = platforminfo.GetOperatingSystemFamilyName();
753 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
754 platforminfo.GetPortIdName();
756 wxLogMessage(wxver +
" " + platform);
758 ::wxGetOsVersion(&osMajor, &osMinor);
759 wxString osVersionMsg;
760 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
761 wxLogMessage(osVersionMsg);
763 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
764 g_mem_total / 1024, g_mem_initial / 1024);
769 if (!detail->osd_names_like.empty())
770 like0 = detail->osd_names_like[0].c_str();
771 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
772 detail->osd_arch.c_str(), detail->osd_name.c_str(),
773 detail->osd_version.c_str(), detail->osd_ID.c_str(),
775 wxLogMessage(msgplat);
777 wxString imsg =
"SData_Locn is ";
778 imsg += g_Platform->GetSharedDataDir();
782 ::wxInitAllImageHandlers();
786 prepareAndroidStyleSheets();
790 pInit_Chart_Dir =
new wxString();
795 imsg =
"PrivateDataDir is ";
801 navutil::InitGlobals();
805 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
809 pSelect->SetSelectPixelRadius(12);
822 g_pais_query_dialog_active = NULL;
825 g_hostname = ::wxGetHostName();
826 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
828 androidGetDeviceInfo();
829 g_hostname = wxString(
"Android-") + g_android_Device_Model;
830 g_hostname.Replace(
" ",
"-",
true);
835 wxString p(
"Portable-");
836 g_hostname = p + g_hostname;
841 pLayerList =
new LayerList;
846 auto &navobj_db = NavObj_dB::GetInstance();
853#ifdef PROBE_PORTS__WITH_HELPER
854 user_user_id = getuid();
855 file_user_id = geteuid();
859 bool b_initial_load =
false;
861 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
862 if (config_test_file_name.FileExists())
863 wxLogMessage(
"Using existing Config_File: " +
864 g_Platform->GetConfigFileName());
867 wxLogMessage(
"Creating new Config_File: " +
868 g_Platform->GetConfigFileName());
870 b_initial_load =
true;
873 config_test_file_name.DirExists(config_test_file_name.GetPath()))
874 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
875 wxLogMessage(
"Cannot create config file directory for " +
876 g_Platform->GetConfigFileName());
881 pConfig = g_Platform->GetConfigObject();
882 InitBaseConfig(pConfig);
883 pConfig->LoadMyConfig();
887 if (b_initial_load) g_Platform->SetDefaultOptions();
889 g_Platform->applyExpertMode(g_bUIexpert);
897 g_StyleManager->SetStyle(
"MUI_flat");
898 if (!g_StyleManager->IsOK()) {
899 wxString msg = _(
"Failed to initialize the user interface. ");
900 msg << _(
"OpenCPN cannot start. ");
901 msg << _(
"The necessary configuration files were not found. ");
902 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
903 << _(
" for details.") <<
"\n\n";
904 msg << g_Platform->GetSharedDataDir();
906 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
907 wxCANCEL | wxICON_ERROR);
914 if (style) style->chartStatusWindowTransparent =
true;
922 msg.Printf(
"Detected display size (horizontal): %d mm",
927 if (g_config_display_size_manual &&
932 msg.Printf(
"Display size (horizontal) config override: %d mm",
941 int SelectPixelRadius = 50;
943 pSelect->SetSelectPixelRadius(SelectPixelRadius);
944 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
945 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
949 if (!n_NavMessageShown) {
956#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
959 g_Platform->SetLocaleSearchPrefixes();
961 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
963 imsg =
"System default Language: " + def_lang_canonical;
966 wxString cflmsg =
"Config file language: " + g_locale;
967 wxLogMessage(cflmsg);
969 if (g_locale.IsEmpty()) {
970 g_locale = def_lang_canonical;
971 cflmsg =
"Config file language empty, using system default: " + g_locale;
972 wxLogMessage(cflmsg);
976 g_locale = g_Platform->GetAdjustedAppLocale();
977 cflmsg =
"Adjusted App language: " + g_locale;
978 wxLogMessage(cflmsg);
981 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
983 imsg =
"Opencpn language set to: ";
990 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
992 wxLogMessage(
"wxLocale support not available");
997 if (g_config_wizard || b_initial_load) {
999 auto res = wiz.Run();
1010 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1011 g_bUpgradeInProcess = (vs != g_config_version_string);
1013 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1016 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1017 wxLogMessage(g_Platform->GetLargeLogMessage());
1022 g_bdisable_opengl =
true;
1026 if (g_bdisable_opengl) g_bopengl =
false;
1028#if defined(__linux__) && !defined(__ANDROID__)
1029 if (g_bSoftwareGL) {
1030 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1043 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1045 wxMin(g_memCacheLimit, 1024 * 1024);
1051 g_memCacheLimit = 0;
1052 if (0 == g_nCacheLimit)
1053 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1058 "chartlist.dat",
"CHRTLIST.DAT");
1062 "mmsitoname.csv",
"MMSINAME.CSV");
1065 if (pInit_Chart_Dir->IsEmpty()) {
1066 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1070 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1072 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1076 InitRestListeners();
1079 gDefaultWorldMapLocation =
"gshhs";
1080 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1081 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1082 if (gWorldMapLocation == wxEmptyString) {
1083 gWorldMapLocation = gDefaultWorldMapLocation;
1088 wxString default_tcdata0 =
1089 (g_Platform->GetSharedDataDir() +
"tcdata" +
1090 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1091 wxString default_tcdata1 =
1092 (g_Platform->GetSharedDataDir() +
"tcdata" +
1093 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1095 if (TideCurrentDataSet.empty()) {
1096 TideCurrentDataSet.push_back(
1097 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1098 TideCurrentDataSet.push_back(
1099 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1104 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1105 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1106 wxFileName::GetPathSeparator() +
"2bells.wav");
1107 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1112 g_Platform->Initialize_2();
1116 wxSize new_frame_size(-1, -1);
1118 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1120 InitializeUserColors();
1122 auto style = g_StyleManager->GetCurrentStyle();
1123 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1125 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1127 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1129 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1130 (g_nframewin_y <= ch))
1131 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1133 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1139 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1140 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1141 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1142 g_bframemax =
false;
1145 g_lastClientRectx = cx;
1146 g_lastClientRecty = cy;
1147 g_lastClientRectw = cw;
1148 g_lastClientRecth = ch;
1151 wxPoint position(0, 0);
1152 wxSize dsize = wxGetDisplaySize();
1155 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1158 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1159 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1164 frame_rect.left = position.x;
1165 frame_rect.top = position.y;
1166 frame_rect.right = position.x + new_frame_size.x;
1167 frame_rect.bottom = position.y + new_frame_size.y;
1171 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1172 position = wxPoint(10, 10);
1177 const wxPoint ptScreen(position.x, position.y);
1178 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1180 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1183 g_nframewin_posx = position.x;
1184 g_nframewin_posy = position.y;
1187 wxSize asz = getAndroidDisplayDimensions();
1192 if ((cw > 200) && (ch > 200))
1193 new_frame_size.Set(cw, ch);
1195 new_frame_size.Set(800, 400);
1199 long app_style = wxDEFAULT_FRAME_STYLE;
1200 app_style |= wxWANTS_CHARS;
1205 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1206 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1209 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1210 myframe_window_title += g_Platform->GetHomeDir();
1211 myframe_window_title +=
"]";
1215 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1216 new_frame_size.x, new_frame_size.y, position.x, position.y);
1220 auto dockart =
new wxAuiDefaultDockArt;
1223 gFrame =
new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1224 app_style, dockart);
1225 wxTheApp->SetTopWindow(gFrame);
1231 g_pauimgr->SetDockSizeConstraint(.9, .9);
1239 g_Platform->Initialize_3();
1241 gFrame->CreateCanvasLayout();
1245 gFrame->SetChartUpdatePeriod();
1249 gFrame->GetPrimaryCanvas()->SetFocus();
1253 gFrame->ApplyGlobalSettings(
false);
1255 gFrame->SetAllToolbarScale();
1261 gFrame->SetAndApplyColorScheme(global_color_scheme);
1263 if (g_bframemax) gFrame->Maximize(
true);
1266 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->
GetPixPerMM() > 4.0))
1267 gFrame->Maximize(
true);
1274 ArrayOfCDI ChartDirArray;
1275 pConfig->LoadChartDirArray(ChartDirArray);
1280 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1283 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1284 if (RegKey.Exists()) {
1286 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1288 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1290 wxStringTokenizer tkz(dirs,
";");
1291 while (tkz.HasMoreTokens()) {
1292 wxString token = tkz.GetNextToken();
1295 cdi.fullpath = token.Trim();
1296 cdi.magic_number =
"";
1298 ChartDirArray.Add(cdi);
1305 cdi.fullpath =
"charts";
1306 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1307 cdi.magic_number =
"";
1308 ChartDirArray.Add(cdi);
1312 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1322 if (!ChartDirArray.GetCount())
1323 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1333 if (g_restore_dbindex >= 0) {
1334 if (
ChartData->GetChartTableEntries() == 0)
1335 g_restore_dbindex = -1;
1337 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1338 g_restore_dbindex = 0;
1350 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1351 g_GLOptions.m_bTextureCompressionCaching) {
1352 gFrame->ReloadAllVP();
1371 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1372 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1375 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1376 wxLogMessage(dogmsg);
1378 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1386 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1393 gFrame->DoChartUpdate();
1398 gFrame->ReloadAllVP();
1400 gFrame->Refresh(
false);
1403 gFrame->GetPrimaryCanvas()->Enable();
1404 gFrame->GetPrimaryCanvas()->SetFocus();
1411 if (!g_bdisable_opengl) {
1414 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1415 gFrame->m_defer_size = gFrame->GetSize();
1416 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1418 gFrame->m_bdefer_resize =
true;
1428 glDeleteTextures(n, texts);
1434 if (g_start_fullscreen) gFrame->ToggleFullScreen();
1439 gFrame->SetSize(getAndroidDisplayDimensions());
1440 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1444 gFrame->GetPrimaryCanvas()->Enable();
1445 gFrame->GetPrimaryCanvas()->SetFocus();
1453 gFrame->FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
1456 gFrame->FrameCOGTimer.Start(2000, wxTIMER_CONTINUOUS);
1459 gFrame->FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
1464 OCPNPlatform::Initialize_4();
1467 androidHideBusyIcon();
1470 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1478 if (!n_NavMessageShown || (vs != g_config_version_string) ||
1479 (g_AndroidVersionCode != androidGetVersionCode())) {
1483 if (!ShowNavWarning()) {
1484 qDebug() <<
"Closing due to NavWarning Cancel";
1490 n_NavMessageShown = 1;
1494 g_AndroidVersionCode = androidGetVersionCode();
1495 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
1500 if (!n_NavMessageShown || (vs != g_config_version_string)) {
1501 if (!ShowNavWarning())
return false;
1502 n_NavMessageShown = 1;
1509 g_bHasHwClock =
true;
1510#if defined(__UNIX__) && !defined(__ANDROID__)
1513 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1514 (stat(
"/dev/misc/rtc", &buffer) == 0));
1517 g_config_version_string = vs;
1520 pConfig->UpdateSettings();
1523 gFrame->InitTimer.Start(5, wxTIMER_CONTINUOUS);
1527 for (
auto *cp : TheConnectionParams()) {
1529 if (cp->GetDSPort().Contains(
"Serial")) {
1530 std::string port(cp->Port.ToStdString());
1538 m_comm_bridge.Initialize();
1540 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1543 if (ipv4_addrs.size()) {
1544 std::string ipAddr = ipv4_addrs[0];
1547 if (data_dir.Last() != wxFileName::GetPathSeparator())
1548 data_dir.Append(wxFileName::GetPathSeparator());
1550 make_certificate(ipAddr, data_dir.ToStdString());
1552 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1553 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1559int MyApp::OnExit() {
1560 wxLogMessage(
"opencpn::MyApp starting exit.");
1562 m_usb_watcher.Stop();
1565 wxDateTime lognow = wxDateTime::Now();
1567 wxString day = lognow.FormatISODate();
1568 wxString utc = lognow.FormatISOTime();
1569 wxString navmsg =
"LOGBOOK: ";
1577 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ",
gLat,
gLon);
1581 if (std::isnan(
gCog))
1582 cog.Printf(
"COG ----- ");
1584 cog.Printf(
"COG %10.5f ",
gCog);
1587 if (std::isnan(
gSog))
1588 sog.Printf(
"SOG ----- ");
1590 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(
gSog));
1597 data.Printf(
"OFF: Lat %10.5f Lon %10.5f",
gLat,
gLon);
1600 wxLogMessage(navmsg);
1601 g_loglast_time = lognow;
1619 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1628 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1629 wxLog::FlushActive();
1631 g_Platform->CloseLogFile();
1633 delete pInit_Chart_Dir;
1641 delete pWayPointMan;
1643 navutil::DeinitGlobals();
1645 DeInitializeUserColors();
1652 delete g_StyleManager;
1657 void RestoreSystemColors();
1658 RestoreSystemColors();
1665#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1666 if (plocale_def_lang)
delete plocale_def_lang;
1669 FontMgr::Shutdown();
1671 g_Platform->OnExit_2();
1678#ifdef LINUX_CRASHRPT
1679void MyApp::OnFatalException() { g_crashprint.Report(); }
1685void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1690 if (eErrClass == CE_Debug)
1691 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1692 else if (eErrClass == CE_Warning)
1693 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1695 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1697 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.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
Manages the chart database and provides access to chart data.
bool LoadBinary(const wxString &filename, ArrayOfCDI &dir_array_check)
Load the chart database from a binary file.
void Notify() override
Notify all listeners, no data supplied.
void ScrubList()
Cleans up stale font entries after a locale change.
static void SeedRandom()
Seed the random generator used by GetUUID().
Common interface for all instance checkers.
virtual bool IsMainInstance()=0
Return true if this process is the primary opencpn instance.
virtual void CleanUp()
Remove all persistent instance state, including possible lock file and defunct opencpn processes.
virtual void OnExit()
Do whatever needed before wxWidget's checks triggers.
virtual void WaitUntilValid()
Wait until this object can be used for example for Dbus connection.
static LocalServerApi & GetInstance()
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
bool LoadAllPlugIns(bool enabled_plugins, bool keep_orphans=false)
Update catalog with imported metadata and load all plugin library files.
bool StartServer(const fs::path &certificate_location) override
Start the server thread.
Represents a waypoint or mark within the navigation system.
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
wxString m_RouteNameString
User-assigned name for the route.
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Window for displaying chart thumbnails.
Represents a track, which is a series of connected track points.
Listen to hardware events and notifies SystemEvents when new devices are plugged in.
OpenGL chart rendering canvas.
Handles crash reporting in wxWidgets applications.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
CommBridge class and helpers.
NMEA Data Multiplexer Object.
Variables maintained by comm stack, read-only access for others.
Primary navigation console display for route and vessel tracking.
Config file user configuration interface.
std::vector< size_t > g_config_display_size_mm
Size of pysical screen in millimeters.
double g_display_size_mm
Physical display width (mm)
Global variables stored in configuration file.
Dump debug info on crash.
Chart display details slider.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
size_t g_current_monitor
Current monitor displaying main application frame.
int g_NeedDBUpdate
0 - No update needed, 1 - Update needed because there is no chart database, inform user 2 - Start upd...
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Instance check interface.
The local API has a server side handling commands and a client part issuing commands.
Enhanced logging interface on top of wx/log.h.
MacOS hardware probing functions.
Waypoint properties maintenance dialog.
Start/stop mdns service routines.
Multiplexer class and helpers.
void check_last_start()
Check if the last start failed, possibly invoke user dialog and set safe mode state.
void clear_check()
Mark last run as successful.
MySQL based storage for routes, tracks, etc.
Navigation Utility Functions without GUI dependencies.
User notifications manager.
s57RegistrarMgr * m_pRegistrarMan
Global instance.
General observable implementation with several specializations.
OCPN_AUIManager * g_pauimgr
Global instance.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Plugin remote repositories installation and Uninstall/list operations.
PlugInManager * g_pi_manager
Global instance.
RoutePoint * pAnchorWatchPoint2
Global instance.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
RoutePoint * pAnchorWatchPoint1
Global instance.
S57 object query result window.
Select * pSelect
Global instance.
Select * pSelectTC
Global instance.
Selected route, segment, waypoint, etc.
SENCThreadManager * g_SencThreadManager
Global instance.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
bool CheckDongleAccess(wxWindow *parent)
Runs checks and if required dialogs to make dongle accessible.
bool CheckSerialAccess(wxWindow *parent, const std::string device)
Run checks and possible dialogs to ensure device is accessible.
Access checks for comm devices and dongle.