63#if (defined(OCPN_GHC_FILESYSTEM) || \
64 (defined(__clang_major__) && (__clang_major__ < 15)))
66#include <ghc/filesystem.hpp>
67namespace fs = ghc::filesystem;
71namespace fs = std::filesystem;
74using namespace std::literals::chrono_literals;
76#include <wx/apptrait.h>
77#include <wx/arrimpl.cpp>
78#include <wx/artprov.h>
79#include <wx/aui/aui.h>
80#include <wx/clrpicker.h>
81#include <wx/cmdline.h>
85#include <wx/display.h>
90#include <wx/jsonreader.h>
91#include <wx/listctrl.h>
93#include <wx/printdlg.h>
95#include <wx/progdlg.h>
96#include <wx/settings.h>
97#include <wx/stdpaths.h>
98#include <wx/tokenzr.h>
102#include "model/certificates.h"
105#include "model/comm_n0183_output.h"
106#include "model/comm_vars.h"
109#include "model/instance_check.h"
116#include "model/nav_object_database.h"
117#include "model/navutil_base.h"
119#include "model/own_ship.h"
121#include "model/route.h"
122#include "model/routeman.h"
123#include "model/select.h"
124#include "model/track.h"
128#include "ais_info_gui.h"
139#include "DetailSlider.h"
142#include "gdal/cpl_csv.h"
143#include "glTexCache.h"
144#include "GoToPositionDialog.h"
150#include "OCPN_AUIManager.h"
151#include "ocpn_frame.h"
152#include "OCPNPlatform.h"
154#include "rest_server_gui.h"
155#include "route_ctx_factory.h"
156#include "routemanagerdialog.h"
157#include "routeman_gui.h"
158#include "RoutePropDlgImpl.h"
161#include "S57QueryDialog.h"
162#include "safe_mode_gui.h"
163#include "SoundFactory.h"
167#include "TrackPropDlg.h"
171#include "glChartCanvas.h"
175#include "model/macutils.h"
179#include "model/garmin_protocol_mgr.h"
180void RedirectIOToConsole();
183#if defined(__WXMSW__) && defined(__MSVC__LEAK)
184#include "Stackwalker.h"
192#include "androidUTIL.h"
198const char *
const kUsage =
201 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
202 opencpn --remote [-R] | -q] | -e] |-o <str>]
204Options for starting opencpn
206 -c, --configdir=<dirpath> Use alternative configuration directory.
207 -p, --portable Run in portable mode.
208 -f, --fullscreen Switch to full screen mode on start.
209 -G, --no_opengl Disable OpenGL video acceleration. This setting will
211 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
212 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
213 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
214 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
215 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
216 Zero or negative <num> specifies no limit.
218 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
219 -W, --config_wizard Start with initial configuration wizard
221Options manipulating already started opencpn
222 -r, --remote Execute commands on already running instance
223 -R, --raise Make running OpenCPN visible if hidden
224 -q, --quit Terminate already running opencpn
225 -e, --get_rest_endpoint Print rest server endpoint and exit.
226 -o, --open=<GPX file> Open file in running opencpn
229 GPX file GPX-formatted file with waypoints or routes.
233wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
234wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
236wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
237wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
238wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
239wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
240wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
241wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
242wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
243wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
244wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
254WX_DEFINE_OBJARRAY(ArrayOfCDI);
257bool g_bUpgradeInProcess;
263LayerList *pLayerList;
265bool g_bshowToolbar =
true;
266bool g_bexpert =
true;
268wxString ChartListFileName;
269wxString gDefaultWorldMapLocation;
270wxString *pInit_Chart_Dir;
272wxString g_VisibleLayers;
273wxString g_InvisibleLayers;
274wxString g_VisiNameinLayers;
275wxString g_InVisiNameinLayers;
277bool g_bcompression_wait;
278int g_FlushNavobjChangesTimeout;
285int g_mem_total, g_mem_initial;
287static unsigned int malloc_max;
289wxDateTime g_start_time;
290wxDateTime g_loglast_time;
291static OcpnSound *_bells_sounds[] = {SoundFactory(), SoundFactory()};
292std::vector<OcpnSound *> bells_sound(_bells_sounds, _bells_sounds + 2);
296bool g_bTransparentToolbar;
297bool g_bTransparentToolbarInOpenGLOK;
299wxArrayPtrVoid *UserColourHashTableArray;
300wxColorHashMap *pcurrent_user_color_hash;
308int g_ChartUpdatePeriod;
310float g_MarkScaleFactorExp;
311int g_last_ChartScaleFactor;
316s57RegistrarMgr *m_pRegistrarMan;
319#include "model/macutils.h"
328extern bool s_glu_dll_ready;
329extern HINSTANCE s_hGLU_DLL;
338long gStart_LMT_Offset;
340wxArrayString *pMessageOnceArray;
344double g_overzoom_emphasis_base;
345bool g_oz_vector_scale;
347std::vector<std::string> TideCurrentDataSet;
349int options_lastPage = 0;
350int options_subpage = 0;
352wxPoint options_lastWindowPos(0, 0);
353wxSize options_lastWindowSize(0, 0);
359bool GetMemoryStatus(
int *mem_total,
int *mem_used);
362bool g_bDeferredStartTrack;
371#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
372wxLocale *plocale_def_lang = 0;
386int g_AisTargetList_count;
387bool g_bAisTargetList_autosort;
389wxAuiDefaultDockArt *g_pauidockart;
394double gQueryVar = 361.0;
396char bells_sound_file_name[2][12] = {
"1bells.wav",
"2bells.wav"};
398int portaudio_initialized;
400char nmea_tick_chars[] = {
'|',
'/',
'-',
'\\',
'|',
'/',
'-',
'\\'};
402int g_sticky_projection;
404int n_NavMessageShown;
405wxString g_config_version_string;
420bool b_inCompressAllCharts;
422wxArrayString g_locale_catalog_array;
423bool b_reloadForPlugins;
424bool g_btrackContinuous;
426bool g_bmasterToolbarFull =
true;
428int g_AndroidVersionCode;
432WX_DEFINE_ARRAY_PTR(
ChartCanvas *, arrayofCanvasPtr);
434arrayofCanvasPtr g_canvasArray;
435wxString g_lastAppliedTemplateGUID;
438bool g_disable_main_toolbar;
439bool g_declutter_anchorage;
440bool g_bhide_route_console;
452DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
453 0x6b, 0xba, 0xe7, 0x22, 0xc0);
457#include <wx/msw/msvcrt.h>
461static const long long lNaN = 0xfff8000000000000;
462#define NAN (*(double *)&lNaN)
466void appendOSDirSlash(wxString *pString);
468void InitializeUserColors(
void);
469void DeInitializeUserColors(
void);
470void SetSystemColors(ColorScheme cs);
472static bool LoadAllPlugIns(
bool load_enabled) {
473 g_Platform->ShowBusySpinner();
474 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
475 g_Platform->HideBusySpinner();
483#if defined(__WXGTK__) || defined(__WXQT__)
484#include "bitmaps/opencpn.xpm"
487wxString newPrivateFileName(wxString,
const char *name,
488 [[maybe_unused]]
const char *windowsName) {
489 wxString fname = wxString::FromUTF8(name);
490 wxString filePathAndName;
493 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
494 filePathAndName.Append(wxFileName::GetPathSeparator());
497 wxString fwname = wxString::FromUTF8(windowsName);
498 filePathAndName.Append(fwname);
500 filePathAndName.Append(fname);
503 return filePathAndName;
512BEGIN_EVENT_TABLE(
MyApp, wxApp)
513EVT_ACTIVATE_APP(MyApp::OnActivateApp)
516static
void ActivateRoute(const std::
string &guid) {
517 Route *route = g_pRouteMan->FindRouteByGUID(guid);
519 wxLogMessage(
"Cannot activate guid: no such route");
522 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
528 point = g_pRouteMan->FindBestActivatePoint(route, gLat, gLon, gCog, gSog);
530 point = route->GetPoint(2);
537static void ReverseRoute(
const std::string &guid) {
538 Route *route = g_pRouteMan->FindRouteByGUID(guid);
540 wxLogMessage(
"Cannot activate guid: no such route");
547void MyApp::InitRestListeners() {
548 auto activate_route = [&](wxCommandEvent ev) {
549 auto guid = ev.GetString().ToStdString();
553 auto reverse_route = [&](wxCommandEvent ev) {
554 auto guid = ev.GetString().ToStdString();
560bool MyApp::OpenFile(
const std::string &path) {
562 auto result = nav_objects.load_file(path.c_str());
564 std::string s(_(
"Cannot load route or waypoint file: "));
565 s += std::string(
"\"") + path +
"\"";
566 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
572 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
574 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
575 pRouteManagerDialog->UpdateLists();
576 LLBBox box = nav_objects.GetBBox();
577 if (box.GetValid()) {
578 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
584void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
587 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
588 parser.AddSwitch(
"p",
"portable");
589 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
590 wxCMD_LINE_PARAM_OPTIONAL);
591 parser.AddSwitch(
"f",
"fullscreen");
592 parser.AddSwitch(
"G",
"no_opengl");
593 parser.AddSwitch(
"W",
"config_wizard");
594 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
595 parser.AddSwitch(
"D",
"rebuild_chart_db");
596 parser.AddSwitch(
"P",
"parse_all_enc");
597 parser.AddOption(
"l",
"loglevel");
598 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
599 parser.AddSwitch(
"U",
"unit_test_2");
600 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
601 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
602 parser.AddSwitch(
"s",
"safe_mode");
603 parser.AddSwitch(
"r",
"remote");
604 parser.AddSwitch(
"R",
"raise");
605 parser.AddSwitch(
"q",
"quit");
606 parser.AddSwitch(
"e",
"get_rest_endpoint");
607 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
608 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
614static void ParseLoglevel(wxCmdLineParser &parser) {
615 wxLog::SetLogLevel(wxLOG_Message);
618static void ParseLoglevel(wxCmdLineParser &parser) {
619 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
620 strLevel = strLevel ? strLevel :
"info";
622 if (parser.Found(
"l", &wxLevel)) {
623 strLevel = wxLevel.c_str();
625 wxLogLevel level = OcpnLog::str2level(strLevel);
626 if (level == OcpnLog::LOG_BADLEVEL) {
627 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
630 wxLog::SetLogLevel(level);
635bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
642bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
647 g_unit_test_2 = parser.Found(
"unit_test_2");
648 g_bportable = parser.Found(
"p");
649 g_start_fullscreen = parser.Found(
"fullscreen");
650 g_bdisable_opengl = parser.Found(
"no_opengl");
651 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
652 g_NeedDBUpdate = parser.Found(
"rebuild_chart_db") ? 2 : 0;
653 g_parse_all_enc = parser.Found(
"parse_all_enc");
654 g_config_wizard = parser.Found(
"config_wizard");
655 if (parser.Found(
"unit_test_1", &number)) {
656 g_unit_test_1 =
static_cast<int>(number);
657 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
659 safe_mode::set_mode(parser.Found(
"safe_mode"));
660 ParseLoglevel(parser);
662 if (parser.Found(
"configdir", &wxstr)) {
663 g_configdir = wxstr.ToStdString();
664 fs::path path(g_configdir);
665 if (!fs::exists(path) || !fs::is_directory(path)) {
666 std::cerr << g_configdir <<
" is not an existing directory.\n";
671 bool has_start_options =
false;
672 static const std::vector<std::string> kStartOptions = {
677 "rebuild_gl_raster_cache",
683 for (
const auto &opt : kStartOptions) {
684 if (parser.Found(opt)) has_start_options =
true;
686 if (has_start_options && parser.Found(
"remote")) {
687 std::cerr <<
"this option is not compatible with --remote\n";
691 bool has_remote_options =
false;
692 static const std::vector<std::string> kRemoteOptions = {
693 "raise",
"quit",
"open",
"get_rest_endpoint"};
694 for (
const auto &opt : kRemoteOptions) {
695 if (parser.Found(opt)) has_remote_options =
true;
697 if (has_remote_options && !parser.Found(
"remote")) {
698 std::cerr <<
"This option requires --remote\n";
702 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
703 g_params.push_back(parser.GetParam(paramNr).ToStdString());
706 if (!parser.Found(
"remote"))
707 m_parsed_cmdline = ParsedCmdline();
708 else if (parser.Found(
"raise"))
709 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
710 else if (parser.Found(
"quit"))
711 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
712 else if (parser.Found(
"get_rest_endpoint"))
713 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
714 else if (parser.Found(
"open", &optarg))
715 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
716 else if (parser.GetParamCount() == 1)
718 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
719 else if (!has_start_options && !has_remote_options) {
721 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
731bool MyApp::OnExceptionInMainLoop() {
732 wxLogWarning(
"Caught MainLoopException, continuing...");
737void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
739static wxStopWatch init_sw;
742 if (m_exitcode != -2)
return m_exitcode;
743 return wxAppConsole::OnRun();
754 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
755 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
756 setenv(
"GDK_BACKEND",
"x11", 1);
760 "mesa_glthread",
"false",
766bool MyApp::OnInit() {
767 if (!wxApp::OnInit())
return false;
769 androidEnableBackButton(
false);
770 androidEnableOptionItems(
false);
775#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
781 wxBitmap bmp(10, 10, -1);
783 dc.SelectObject(bmp);
784 dc.DrawText(
"X", 0, 0);
789 g_BasePlatform = g_Platform;
796 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
800 std::cerr <<
"No remote opencpn found. Giving up.\n";
805 std::unique_ptr<LocalClientApi> client;
807 client = LocalClientApi::GetClient();
809 WARNING_LOG <<
"Ipc client exception: " << ie.str();
816 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
817 "to respond.\nPlease retry."),
818 "OpenCPN", wxICON_INFORMATION | wxOK);
823 auto result = client->HandleCmdline(m_parsed_cmdline.action,
824 m_parsed_cmdline.arg);
828 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
837 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
838 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
843 if (!safe_mode::get_mode()) {
849 OCPNPlatform::Initialize_1();
854 MyApp::SetAppDisplayName(
"OpenCPN");
857 wxDateTime x = wxDateTime::UNow();
858 long seed = x.GetMillisecond();
859 seed *= x.GetTicks();
864 setlocale(LC_NUMERIC,
"C");
866 g_start_time = wxDateTime::Now();
868 g_loglast_time = g_start_time;
869 g_loglast_time.MakeGMT();
870 g_loglast_time.Subtract(
871 wxTimeSpan(0, 29, 0, 0));
873 AnchorPointMinDist = 5.0;
879 GetMemoryStatus(&g_mem_total, &g_mem_initial);
883 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
884 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
885 wxFONTENCODING_SYSTEM);
886 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
889 auto ¬eman = NotificationManager::GetInstance();
890 noteman.ScrubNotificationDirectory(30);
893 if (!g_Platform->InitializeLogFile()) {
905 wxLogMessage(
"\n\n________\n");
907 wxDateTime now = wxDateTime::Now();
908 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
909 now.FormatISODate().mb_str().data());
910 wxLogLevel level = wxLog::GetLogLevel();
911 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
913 wxString wxver(wxVERSION_STRING);
914 wxver.Prepend(
"wxWidgets version: ");
916 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
920 os_name = platforminfo.GetOperatingSystemIdName();
922 os_name = platforminfo.GetOperatingSystemFamilyName();
925 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
926 platforminfo.GetPortIdName();
928 wxLogMessage(wxver +
" " + platform);
930 ::wxGetOsVersion(&osMajor, &osMinor);
931 wxString osVersionMsg;
932 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
933 wxLogMessage(osVersionMsg);
935 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
936 g_mem_total / 1024, g_mem_initial / 1024);
941 if (!detail->osd_names_like.empty())
942 like0 = detail->osd_names_like[0].c_str();
943 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
944 detail->osd_arch.c_str(), detail->osd_name.c_str(),
945 detail->osd_version.c_str(), detail->osd_ID.c_str(),
947 wxLogMessage(msgplat);
949 wxString imsg =
"SData_Locn is ";
950 imsg += g_Platform->GetSharedDataDir();
954 ::wxInitAllImageHandlers();
958 prepareAndroidStyleSheets();
962 pInit_Chart_Dir =
new wxString();
967 imsg =
"PrivateDataDir is ";
973 pMessageOnceArray =
new wxArrayString;
977 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
981 pSelect->SetSelectPixelRadius(12);
986 pSelectTC->SetSelectPixelRadius(25);
989 pSelectAIS =
new Select();
990 pSelectAIS->SetSelectPixelRadius(12);
994 g_pais_query_dialog_active = NULL;
997 g_hostname = ::wxGetHostName();
998 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
1000 androidGetDeviceInfo();
1001 g_hostname = wxString(
"Android-") + g_android_Device_Model;
1002 g_hostname.Replace(
" ",
"-",
true);
1007 wxString p(
"Portable-");
1008 g_hostname = p + g_hostname;
1013 pLayerList =
new LayerList;
1015 pRouteList =
new RouteList;
1018 auto &navobj_db = NavObj_dB::GetInstance();
1025#ifdef PROBE_PORTS__WITH_HELPER
1026 user_user_id = getuid();
1027 file_user_id = geteuid();
1031 bool b_initial_load =
false;
1033 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
1034 if (config_test_file_name.FileExists())
1035 wxLogMessage(
"Using existing Config_File: " +
1036 g_Platform->GetConfigFileName());
1039 wxLogMessage(
"Creating new Config_File: " +
1040 g_Platform->GetConfigFileName());
1042 b_initial_load =
true;
1045 config_test_file_name.DirExists(config_test_file_name.GetPath()))
1046 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
1047 wxLogMessage(
"Cannot create config file directory for " +
1048 g_Platform->GetConfigFileName());
1053 pConfig = g_Platform->GetConfigObject();
1054 InitBaseConfig(pConfig);
1055 pConfig->LoadMyConfig();
1059 if (b_initial_load) g_Platform->SetDefaultOptions();
1061 g_Platform->applyExpertMode(g_bUIexpert);
1069 g_StyleManager->SetStyle(
"MUI_flat");
1070 if (!g_StyleManager->IsOK()) {
1071 wxString msg = _(
"Failed to initialize the user interface. ");
1072 msg << _(
"OpenCPN cannot start. ");
1073 msg << _(
"The necessary configuration files were not found. ");
1074 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
1075 << _(
" for details.") <<
"\n\n";
1076 msg << g_Platform->GetSharedDataDir();
1078 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
1079 wxCANCEL | wxICON_ERROR);
1086 if (style) style->chartStatusWindowTransparent =
true;
1090 pWayPointMan = NULL;
1094 msg.Printf(
"Detected display size (horizontal): %d mm",
1099 if (g_config_display_size_manual &&
1104 msg.Printf(
"Display size (horizontal) config override: %d mm",
1113 int SelectPixelRadius = 50;
1115 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1116 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1117 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1121 if (!n_NavMessageShown) {
1128#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1131 g_Platform->SetLocaleSearchPrefixes();
1133 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1135 imsg =
"System default Language: " + def_lang_canonical;
1138 wxString cflmsg =
"Config file language: " + g_locale;
1139 wxLogMessage(cflmsg);
1141 if (g_locale.IsEmpty()) {
1142 g_locale = def_lang_canonical;
1143 cflmsg =
"Config file language empty, using system default: " + g_locale;
1144 wxLogMessage(cflmsg);
1148 g_locale = g_Platform->GetAdjustedAppLocale();
1149 cflmsg =
"Adjusted App language: " + g_locale;
1150 wxLogMessage(cflmsg);
1153 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1155 imsg =
"Opencpn language set to: ";
1162 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1164 wxLogMessage(
"wxLocale support not available");
1169 if (g_config_wizard || b_initial_load) {
1171 auto res = wiz.Run();
1182 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1183 g_bUpgradeInProcess = (vs != g_config_version_string);
1185 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1188 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1189 wxLogMessage(g_Platform->GetLargeLogMessage());
1194 g_bdisable_opengl =
true;
1198 if (g_bdisable_opengl) g_bopengl =
false;
1200#if defined(__linux__) && !defined(__ANDROID__)
1201 if (g_bSoftwareGL) {
1202 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1215 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1217 wxMin(g_memCacheLimit, 1024 * 1024);
1223 g_memCacheLimit = 0;
1224 if (0 == g_nCacheLimit)
1225 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1230 "chartlist.dat",
"CHRTLIST.DAT");
1234 "mmsitoname.csv",
"MMSINAME.CSV");
1237 if (pInit_Chart_Dir->IsEmpty()) {
1238 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1242 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1244 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1248 InitRestListeners();
1251 gDefaultWorldMapLocation =
"gshhs";
1252 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1253 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1254 if (gWorldMapLocation == wxEmptyString) {
1255 gWorldMapLocation = gDefaultWorldMapLocation;
1260 wxString default_tcdata0 =
1261 (g_Platform->GetSharedDataDir() +
"tcdata" +
1262 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1263 wxString default_tcdata1 =
1264 (g_Platform->GetSharedDataDir() +
"tcdata" +
1265 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1267 if (TideCurrentDataSet.empty()) {
1268 TideCurrentDataSet.push_back(
1269 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1270 TideCurrentDataSet.push_back(
1271 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1276 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1277 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1278 wxFileName::GetPathSeparator() +
"2bells.wav");
1279 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1284 g_Platform->Initialize_2();
1288 wxSize new_frame_size(-1, -1);
1290 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1292 InitializeUserColors();
1294 auto style = g_StyleManager->GetCurrentStyle();
1295 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1297 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1299 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1301 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1302 (g_nframewin_y <= ch))
1303 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1305 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1311 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1312 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1313 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1314 g_bframemax =
false;
1317 g_lastClientRectx = cx;
1318 g_lastClientRecty = cy;
1319 g_lastClientRectw = cw;
1320 g_lastClientRecth = ch;
1323 wxPoint position(0, 0);
1324 wxSize dsize = wxGetDisplaySize();
1327 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1330 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1331 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1336 frame_rect.left = position.x;
1337 frame_rect.top = position.y;
1338 frame_rect.right = position.x + new_frame_size.x;
1339 frame_rect.bottom = position.y + new_frame_size.y;
1343 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1344 position = wxPoint(10, 10);
1349 const wxPoint ptScreen(position.x, position.y);
1350 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1352 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1355 g_nframewin_posx = position.x;
1356 g_nframewin_posy = position.y;
1359 wxSize asz = getAndroidDisplayDimensions();
1364 if ((cw > 200) && (ch > 200))
1365 new_frame_size.Set(cw, ch);
1367 new_frame_size.Set(800, 400);
1371 long app_style = wxDEFAULT_FRAME_STYLE;
1372 app_style |= wxWANTS_CHARS;
1377 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1378 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1381 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1382 myframe_window_title += g_Platform->GetHomeDir();
1383 myframe_window_title +=
"]";
1387 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1388 new_frame_size.x, new_frame_size.y, position.x, position.y);
1391 gFrame =
new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1393 wxTheApp->SetTopWindow(gFrame);
1396 g_Platform->Initialize_3();
1403 g_pauidockart =
new wxAuiDefaultDockArt;
1404 g_pauimgr->SetArtProvider(g_pauidockart);
1405 g_pauimgr->SetDockSizeConstraint(.9, .9);
1410 g_pauimgr->SetManagedWindow(gFrame);
1412 gFrame->CreateCanvasLayout();
1416 gFrame->SetChartUpdatePeriod();
1420 gFrame->GetPrimaryCanvas()->SetFocus();
1422 pthumbwin =
new ThumbWin(gFrame->GetPrimaryCanvas());
1424 gFrame->ApplyGlobalSettings(
false);
1426 gFrame->SetAllToolbarScale();
1432 gFrame->SetAndApplyColorScheme(global_color_scheme);
1434 if (g_bframemax) gFrame->Maximize(
true);
1437 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->GetPixPerMM() > 4.0))
1438 gFrame->Maximize(
true);
1445 ArrayOfCDI ChartDirArray;
1446 pConfig->LoadChartDirArray(ChartDirArray);
1451 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1454 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1455 if (RegKey.Exists()) {
1457 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1459 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1461 wxStringTokenizer tkz(dirs,
";");
1462 while (tkz.HasMoreTokens()) {
1463 wxString token = tkz.GetNextToken();
1466 cdi.fullpath = token.Trim();
1467 cdi.magic_number =
"";
1469 ChartDirArray.Add(cdi);
1476 cdi.fullpath =
"charts";
1477 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1478 cdi.magic_number =
"";
1479 ChartDirArray.Add(cdi);
1483 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1493 if (!ChartDirArray.GetCount())
1494 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1498 if (g_NeedDBUpdate == 0 &&
1504 if (g_restore_dbindex >= 0) {
1505 if (
ChartData->GetChartTableEntries() == 0)
1506 g_restore_dbindex = -1;
1508 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1509 g_restore_dbindex = 0;
1521 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1522 g_GLOptions.m_bTextureCompressionCaching) {
1523 gFrame->ReloadAllVP();
1532 if (g_glTextureManager) g_glTextureManager->BuildCompressedCache();
1542 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1543 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1546 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1547 wxLogMessage(dogmsg);
1549 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1557 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1559 pAnchorWatchPoint1 = NULL;
1560 pAnchorWatchPoint2 = NULL;
1564 gFrame->DoChartUpdate();
1569 gFrame->ReloadAllVP();
1571 gFrame->Refresh(
false);
1574 gFrame->GetPrimaryCanvas()->Enable();
1575 gFrame->GetPrimaryCanvas()->SetFocus();
1582 if (!g_bdisable_opengl) {
1585 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1586 gFrame->m_defer_size = gFrame->GetSize();
1587 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1588 g_pauimgr->Update();
1589 gFrame->m_bdefer_resize =
true;
1599 glDeleteTextures(n, texts);
1605 if (g_start_fullscreen) gFrame->ToggleFullScreen();
1610 gFrame->SetSize(getAndroidDisplayDimensions());
1611 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1615 gFrame->GetPrimaryCanvas()->Enable();
1616 gFrame->GetPrimaryCanvas()->SetFocus();
1624 gFrame->FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
1627 gFrame->FrameCOGTimer.Start(2000, wxTIMER_CONTINUOUS);
1630 gFrame->FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
1635 OCPNPlatform::Initialize_4();
1638 androidHideBusyIcon();
1641 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1649 if (!n_NavMessageShown || (vs != g_config_version_string) ||
1650 (g_AndroidVersionCode != androidGetVersionCode())) {
1654 if (!ShowNavWarning()) {
1655 qDebug() <<
"Closing due to NavWarning Cancel";
1661 n_NavMessageShown = 1;
1665 g_AndroidVersionCode = androidGetVersionCode();
1666 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
1671 if (!n_NavMessageShown || (vs != g_config_version_string)) {
1672 if (!ShowNavWarning())
return false;
1673 n_NavMessageShown = 1;
1680 g_bHasHwClock =
true;
1681#if defined(__UNIX__) && !defined(__ANDROID__)
1684 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1685 (stat(
"/dev/misc/rtc", &buffer) == 0));
1688 g_config_version_string = vs;
1691 pConfig->UpdateSettings();
1694 gFrame->InitTimer.Start(5, wxTIMER_CONTINUOUS);
1696 g_pauimgr->Update();
1698 for (
auto *cp : TheConnectionParams()) {
1700 if (cp->GetDSPort().Contains(
"Serial")) {
1701 std::string port(cp->Port.ToStdString());
1709 m_comm_bridge.Initialize();
1711 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1714 if (ipv4_addrs.size()) {
1715 std::string ipAddr = ipv4_addrs[0];
1718 if (data_dir.Last() != wxFileName::GetPathSeparator())
1719 data_dir.Append(wxFileName::GetPathSeparator());
1721 make_certificate(ipAddr, data_dir.ToStdString());
1723 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1724 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1730int MyApp::OnExit() {
1731 wxLogMessage(
"opencpn::MyApp starting exit.");
1733 m_usb_watcher.Stop();
1736 wxDateTime lognow = wxDateTime::Now();
1738 wxString day = lognow.FormatISODate();
1739 wxString utc = lognow.FormatISOTime();
1740 wxString navmsg =
"LOGBOOK: ";
1748 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ", gLat, gLon);
1752 if (std::isnan(gCog))
1753 cog.Printf(
"COG ----- ");
1755 cog.Printf(
"COG %10.5f ", gCog);
1758 if (std::isnan(gSog))
1759 sog.Printf(
"SOG ----- ");
1761 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(gSog));
1768 data.Printf(
"OFF: Lat %10.5f Lon %10.5f", gLat, gLon);
1771 wxLogMessage(navmsg);
1772 g_loglast_time = lognow;
1774 if (ptcmgr)
delete ptcmgr;
1776 for (
Track *track : g_TrackList) {
1779 g_TrackList.clear();
1787 delete g_SencThreadManager;
1790 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1799 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1800 wxLog::FlushActive();
1802 g_Platform->CloseLogFile();
1804 delete pInit_Chart_Dir;
1806 for (
Track *track : g_TrackList) {
1809 g_TrackList.clear();
1812 delete pWayPointMan;
1814 delete pMessageOnceArray;
1816 DeInitializeUserColors();
1820 delete m_pRegistrarMan;
1823 delete g_StyleManager;
1828 if (s_glu_dll_ready) {
1829 FreeLibrary(s_hGLU_DLL);
1838 void RestoreSystemColors(
void);
1839 RestoreSystemColors();
1846#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1847 if (plocale_def_lang)
delete plocale_def_lang;
1850 FontMgr::Shutdown();
1852 g_Platform->OnExit_2();
1859#ifdef LINUX_CRASHRPT
1860void MyApp::OnFatalException() { g_crashprint.Report(); }
1866void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1871 if (eErrClass == CE_Debug)
1872 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1873 else if (eErrClass == CE_Warning)
1874 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1876 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1878 wxString str(msg, wxConvUTF8);
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetListDialog.
Class AISTargetQueryDialog.
Chart canvas configuration state
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Generic Chart canvas base.
Extends AboutFrame, providing implementation for various event handlers and additional methods.
EventVar reverse_route
Notified with a string GUID when user wants to reverse a route.
EventVar activate_route
Notified with a string GUID when user wants to activate a route.
Handles the AIS information GUI and sound alerts.
ChartCanvas - Main chart display and interaction component.
Manages the chart database and provides access to chart data.
bool LoadBinary(const wxString &filename, ArrayOfCDI &dir_array_check)
Load the chart database from a binary file.
void Notify() override
Notify all listeners, no data supplied.
void ScrubList()
Cleans up stale font entries after a locale change.
static void SeedRandom()
Seed the random generator used by GetUUID().
Common interface for all instance checkers.
virtual bool IsMainInstance()=0
Return true if this process is the primary opencpn instance.
virtual void CleanUp()
Remove all persistent instance state, including possible lock file and defunct opencpn processes.
virtual void OnExit()
Do whatever needed before wxWidget's checks triggers.
virtual void WaitUntilValid()
Wait until this object can be used for example for Dbus connection.
static LocalServerApi & GetInstance()
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
bool LoadAllPlugIns(bool enabled_plugins, bool keep_orphans=false)
Update catalog with imported metadata and load all plugin library files.
bool StartServer(const fs::path &certificate_location) override
Start the server thread.
Represents a waypoint or mark within the navigation system.
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
wxString m_RouteNameString
User-assigned name for the route.
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Window for displaying chart thumbnails.
Represents a track, which is a series of connected track points.
Listen to hardware events and notifies SystemEvents when new devices are plugged in.
OpenGL chart rendering canvas.
Handles crash reporting in wxWidgets applications.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
The CommBridge class and helpers.
Primary navigation console display for route and vessel tracking.
Config file user configuration interface.
std::vector< size_t > g_config_display_size_mm
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.
Miscellaneous globals primarely used by gui layer.
The local API has a server side handling commands and a client part issuing commands.
Enhanced logging interface on top of wx/log.h.
Start/stop mdns service routines.
Multiplexer class and helpers.
void check_last_start()
Check if the last start failed, possibly invoke user dialog and set safe mode state.
void clear_check()
Mark last run as successful.
Class NotificationManager.
General observable implementation with several specializations.
PLugin remote repositories installation and Uninstall/list operations.
bool CheckDongleAccess(wxWindow *parent)
Runs checks and if required dialogs to make dongle accessible.
bool CheckSerialAccess(wxWindow *parent, const std::string device)
Run checks and possible dialogs to ensure device is accessible.
Access checks for comm devices and dongle.