53typedef struct _GdkWindow GdkWindow;
54typedef struct _GtkWidget GtkWidget;
56void gtk_widget_realize(GtkWidget *widget);
57GdkWindow *gtk_widget_get_window(GtkWidget *widget);
58void gdk_window_set_override_redirect(GdkWindow *window,
59 gboolean override_redirect);
66#include <wx/msw/msvcrt.h>
78#if defined(__WXMSW__) && defined(__MSVC__LEAK)
79#include "Stackwalker.h"
88#include <wx/apptrait.h>
89#include <wx/arrimpl.cpp>
90#include <wx/artprov.h>
91#include <wx/aui/aui.h>
92#include <wx/aui/dockart.h>
93#include <wx/clrpicker.h>
94#include <wx/cmdline.h>
98#include <wx/display.h>
103#include <wx/jsonreader.h>
104#include <wx/listctrl.h>
106#include <wx/printdlg.h>
108#include <wx/progdlg.h>
109#include <wx/settings.h>
110#include <wx/stdpaths.h>
111#include <wx/tokenzr.h>
113#include "o_sound/o_sound.h"
133#include "model/nav_object_database.h"
145#include "ais_info_gui.h"
157#include "dialog_alert.h"
160#include "gdal/cpl_csv.h"
174#include "route_ctx_factory.h"
181#include "safe_mode_gui.h"
182#include "std_filesystem.h"
188#include "user_colors.h"
201void RedirectIOToConsole();
213#include "androidUTIL.h"
218using namespace std::literals::chrono_literals;
220const char *
const kUsage =
223 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
224 opencpn --remote [-R] | -q] | -e] |-o <str>]
226Options for starting opencpn
228 -c, --configdir=<dirpath> Use alternative configuration directory.
229 -p, --portable Run in portable mode.
230 -f, --fullscreen Switch to full screen mode on start.
231 -G, --no_opengl Disable OpenGL video acceleration. This setting will
233 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
234 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
235 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
236 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
237 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
238 Zero or negative <num> specifies no limit.
240 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
241 -W, --config_wizard Start with initial configuration wizard
243Options manipulating already started opencpn
244 -r, --remote Execute commands on already running instance
245 -R, --raise Make running OpenCPN visible if hidden
246 -q, --quit Terminate already running opencpn
247 -e, --get_rest_endpoint Print rest server endpoint and exit.
248 -o, --open=<GPX file> Open file in running opencpn
251 GPX file GPX-formatted file with waypoints or routes.
255wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
256wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
258wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
259wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
260wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
261wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
262wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
263wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
264wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
265wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
266wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
276WX_DEFINE_OBJARRAY(ArrayOfCDI);
278static int user_user_id;
279static int file_user_id;
281static int g_mem_total, g_mem_initial;
283static unsigned int malloc_max;
285static int osMajor, osMinor;
287static bool g_bHasHwClock;
289#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
291wxLocale *plocale_def_lang = 0;
299extern sigjmp_buf env;
304DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
305 0x6b, 0xba, 0xe7, 0x22, 0xc0);
309static const long long lNaN = 0xfff8000000000000;
310#define NAN (*(double *)&lNaN)
314void appendOSDirSlash(wxString *pString);
316void InitializeUserColors();
317void DeInitializeUserColors();
318void SetSystemColors(ColorScheme cs);
320static bool LoadAllPlugIns(
bool load_enabled) {
321 g_Platform->ShowBusySpinner();
322 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
323 g_Platform->HideBusySpinner();
331#if defined(__WXGTK__) || defined(__WXQT__)
332#include "bitmaps/opencpn.xpm"
335static wxString newPrivateFileName(wxString,
const char *name,
336 [[maybe_unused]]
const char *windowsName) {
337 wxString fname = wxString::FromUTF8(name);
338 wxString filePathAndName;
341 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
342 filePathAndName.Append(wxFileName::GetPathSeparator());
345 wxString fwname = wxString::FromUTF8(windowsName);
346 filePathAndName.Append(fwname);
348 filePathAndName.Append(fname);
351 return filePathAndName;
354void MyApp::OnNewMsgTypes() {
355 for (
auto it : m_api_events_callbacks)
356 it.second(
HostApi122::EventType::kNewMessageType);
359void MyApp::RegisterApiEventCallback(
360 const std::string &plugin_name,
363 m_api_events_callbacks[plugin_name] = std::move(callback);
365 m_api_events_callbacks.erase(plugin_name);
371 : wxFrame(
nullptr, wxID_ANY,
"Loading...", wxDefaultPosition,
372 wxSize(2000, 2000), wxSTAY_ON_TOP) {
374 SetBackgroundColour(wxColour(0, 0, 0));
376 wxPanel *panel =
new wxPanel(
this, wxID_ANY);
379 panel->SetBackgroundColour(wxColour(0, 0, 0));
382 wxBoxSizer *sizer =
new wxBoxSizer(wxVERTICAL);
383 sizer->Add(panel, 1, wxEXPAND);
393 GtkWidget *widget =
reinterpret_cast<GtkWidget *
>(GetHandle());
395 gtk_widget_realize(widget);
396 GdkWindow *gdk = gtk_widget_get_window(widget);
398 gdk_window_set_override_redirect(gdk, 1);
405bool ShowNavWarning() {
408OpenCPN is distributed in the hope that it will be useful, \
409but WITHOUT ANY WARRANTY; without even the implied \
410warranty of MERCHANTABILITY or FITNESS FOR A \
411PARTICULAR PURPOSE.\n\n\
412See the GNU General Public License for more details.\n\n\
413OpenCPN must only be used in conjunction with approved \
414paper charts and traditional methods of navigation.\n\n\
415DO NOT rely upon OpenCPN for safety of life or property.\n\n\
416Please click \"Agree\" and proceed, or \"Cancel\" to quit.\n"));
418 wxString vs = wxString::Format(
" .. Version %s", VERSION_FULL);
421 androidShowDisclaimer(_(
"OpenCPN for Android") + vs, msg);
424 msg.Replace(
"\n",
"<br>");
426 std::stringstream html;
427 html <<
"<html><body><p>";
428 html << msg.ToStdString();
429 html <<
"</p></body></html>";
431 std::string title = _(
"Welcome to OpenCPN").ToStdString();
432 std::string action = _(
"Agree").ToStdString();
434 info_dlg.SetInitialSize();
435 info_dlg.AddHtmlContent(html);
436 int agreed = info_dlg.ShowModal();
437 return agreed == wxID_OK;
441bool DoNavMessage(wxString &new_version_string) {
446 if (!n_NavMessageShown || (new_version_string != g_config_version_string) ||
447 (g_AndroidVersionCode != androidGetVersionCode())) {
451 if (!ShowNavWarning()) {
452 qDebug() <<
"Closing due to NavWarning Cancel";
458 n_NavMessageShown = 1;
462 g_AndroidVersionCode = androidGetVersionCode();
463 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
468 if (!n_NavMessageShown || (new_version_string != g_config_version_string)) {
469 if (!ShowNavWarning())
return false;
470 n_NavMessageShown = 1;
483BEGIN_EVENT_TABLE(
MyApp, wxApp)
484EVT_ACTIVATE_APP(MyApp::OnActivateApp)
487static
void ActivateRoute(const std::
string &guid) {
490 wxLogMessage(
"Cannot activate guid: no such route");
501 point = route->GetPoint(2);
508static void ReverseRoute(
const std::string &guid) {
511 wxLogMessage(
"Cannot activate guid: no such route");
518void MyApp::InitRestListeners() {
519 auto activate_route = [&](wxCommandEvent ev) {
520 auto guid = ev.GetString().ToStdString();
524 auto reverse_route = [&](wxCommandEvent ev) {
525 auto guid = ev.GetString().ToStdString();
531void MyApp::OnUnhandledException() {
538 }
catch (std::exception &e) {
540 what.Printf(
"standard exception with message \"%s\"", e.what());
542 what.Printf(
"standard exception of type \"%s\" with message \"%s\"",
543 typeid(e).name(), e.what());
546 what =
"unknown exception";
548 wxMessageOutputBest().Printf(
549 "Unhandled %s; terminating %s.\n", what,
550 wxIsMainThread() ?
"the application" :
"the thread in which it happened");
553bool MyApp::OpenFile(
const std::string &path) {
555 auto result = nav_objects.load_file(path.c_str());
557 std::string s(_(
"Cannot load route or waypoint file: "));
558 s += std::string(
"\"") + path +
"\"";
559 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
565 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
569 LLBBox box = nav_objects.GetBBox();
570 if (box.GetValid()) {
571 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
577void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
580 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
581 parser.AddSwitch(
"p",
"portable");
582 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
583 wxCMD_LINE_PARAM_OPTIONAL);
584 parser.AddSwitch(
"f",
"fullscreen");
585 parser.AddSwitch(
"G",
"no_opengl");
586 parser.AddSwitch(
"W",
"config_wizard");
587 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
588 parser.AddSwitch(
"D",
"rebuild_chart_db");
589 parser.AddSwitch(
"P",
"parse_all_enc");
590 parser.AddOption(
"l",
"loglevel");
591 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
592 parser.AddSwitch(
"U",
"unit_test_2");
593 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
594 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
595 parser.AddSwitch(
"s",
"safe_mode");
596 parser.AddSwitch(
"r",
"remote");
597 parser.AddSwitch(
"R",
"raise");
598 parser.AddSwitch(
"q",
"quit");
599 parser.AddSwitch(
"e",
"get_rest_endpoint");
600 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
601 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
607static void ParseLoglevel(wxCmdLineParser &parser) {
608 wxLog::SetLogLevel(wxLOG_Message);
611static void ParseLoglevel(wxCmdLineParser &parser) {
612 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
613 strLevel = strLevel ? strLevel :
"info";
615 if (parser.Found(
"l", &wxLevel)) {
616 strLevel = wxLevel.c_str();
618 wxLogLevel level = OcpnLog::str2level(strLevel);
619 if (level == OcpnLog::LOG_BADLEVEL) {
620 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
623 wxLog::SetLogLevel(level);
628bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
635bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
640 g_unit_test_2 = parser.Found(
"unit_test_2");
641 g_bportable = parser.Found(
"p");
642 g_start_fullscreen = parser.Found(
"fullscreen");
643 g_bdisable_opengl = parser.Found(
"no_opengl");
644 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
646 g_parse_all_enc = parser.Found(
"parse_all_enc");
647 g_config_wizard = parser.Found(
"config_wizard");
648 if (parser.Found(
"unit_test_1", &number)) {
649 g_unit_test_1 =
static_cast<int>(number);
650 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
652 safe_mode::set_mode(parser.Found(
"safe_mode"));
653 ParseLoglevel(parser);
655 if (parser.Found(
"configdir", &wxstr)) {
656 g_configdir = wxstr.ToStdString();
657 fs::path path(g_configdir);
658 if (!fs::exists(path) || !fs::is_directory(path)) {
659 std::cerr << g_configdir <<
" is not an existing directory.\n";
664 bool has_start_options =
false;
665 static const std::vector<std::string> kStartOptions = {
670 "rebuild_gl_raster_cache",
676 for (
const auto &opt : kStartOptions) {
677 if (parser.Found(opt)) has_start_options =
true;
679 if (has_start_options && parser.Found(
"remote")) {
680 std::cerr <<
"this option is not compatible with --remote\n";
684 bool has_remote_options =
false;
685 static const std::vector<std::string> kRemoteOptions = {
686 "raise",
"quit",
"open",
"get_rest_endpoint"};
687 for (
const auto &opt : kRemoteOptions) {
688 if (parser.Found(opt)) has_remote_options =
true;
690 if (has_remote_options && !parser.Found(
"remote")) {
691 std::cerr <<
"This option requires --remote\n";
695 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
696 g_params.push_back(parser.GetParam(paramNr).ToStdString());
699 if (!parser.Found(
"remote"))
700 m_parsed_cmdline = ParsedCmdline();
701 else if (parser.Found(
"raise"))
702 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
703 else if (parser.Found(
"quit"))
704 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
705 else if (parser.Found(
"get_rest_endpoint"))
706 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
707 else if (parser.Found(
"open", &optarg))
708 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
709 else if (parser.GetParamCount() == 1)
711 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
712 else if (!has_start_options && !has_remote_options) {
714 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
724bool MyApp::OnExceptionInMainLoop() {
725 wxLogWarning(
"Caught MainLoopException, continuing...");
730void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
732static wxStopWatch init_sw;
735 if (m_exitcode != -2)
return m_exitcode;
736 return wxAppConsole::OnRun();
747 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
748 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
749 setenv(
"GDK_BACKEND",
"x11", 1);
753 "mesa_glthread",
"false",
762 if (!wxApp::OnInit())
return false;
765 androidEnableBackButton(
false);
766 androidEnableOptionItems(
false);
771#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
777 wxBitmap bmp(10, 10, -1);
779 dc.SelectObject(bmp);
780 dc.DrawText(
"X", 0, 0);
795 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
799 std::cerr <<
"No remote opencpn found. Giving up.\n";
804 std::unique_ptr<LocalClientApi> client;
806 client = LocalClientApi::GetClient();
808 WARNING_LOG <<
"Ipc client exception: " << ie.str();
815 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
816 "to respond.\nPlease retry."),
817 "OpenCPN", wxICON_INFORMATION | wxOK);
822 auto result = client->HandleCmdline(m_parsed_cmdline.action,
823 m_parsed_cmdline.arg);
827 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
836 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
837 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
842 if (!safe_mode::get_mode()) {
848 OCPNPlatform::Initialize_1();
853 MyApp::SetAppDisplayName(
"OpenCPN");
856 wxDateTime x = wxDateTime::UNow();
857 long seed = x.GetMillisecond();
858 seed *= x.GetTicks();
863 setlocale(LC_NUMERIC,
"C");
865 g_start_time = wxDateTime::Now();
867 g_loglast_time = g_start_time;
868 g_loglast_time.MakeGMT();
869 g_loglast_time.Subtract(
870 wxTimeSpan(0, 29, 0, 0));
872 AnchorPointMinDist = 5.0;
878 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
882 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
883 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
884 wxFONTENCODING_SYSTEM);
885 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
888 auto ¬eman = NotificationManager::GetInstance();
889 noteman.ScrubNotificationDirectory(30);
892 if (!g_Platform->InitializeLogFile()) {
904 wxLogMessage(
"\n\n________\n");
906 wxDateTime now = wxDateTime::Now();
907 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
908 now.FormatISODate().mb_str().data());
909 wxLogLevel level = wxLog::GetLogLevel();
910 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
912 wxString wxver(wxVERSION_STRING);
913 wxver.Prepend(
"wxWidgets version: ");
915 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
919 os_name = platforminfo.GetOperatingSystemIdName();
921 os_name = platforminfo.GetOperatingSystemFamilyName();
924 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
925 platforminfo.GetPortIdName();
927 wxLogMessage(wxver +
" " + platform);
929 ::wxGetOsVersion(&osMajor, &osMinor);
930 wxString osVersionMsg;
931 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
932 wxLogMessage(osVersionMsg);
934 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
935 g_mem_total / 1024, g_mem_initial / 1024);
940 if (!detail->osd_names_like.empty())
941 like0 = detail->osd_names_like[0].c_str();
942 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
943 detail->osd_arch.c_str(), detail->osd_name.c_str(),
944 detail->osd_version.c_str(), detail->osd_ID.c_str(),
946 wxLogMessage(msgplat);
948 wxString imsg =
"SData_Locn is ";
949 imsg += g_Platform->GetSharedDataDir();
953 ::wxInitAllImageHandlers();
957 prepareAndroidStyleSheets();
961 pInit_Chart_Dir =
new wxString();
966 imsg =
"PrivateDataDir is ";
972 navutil::InitGlobals();
976 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
980 pSelect->SetSelectPixelRadius(12);
993 g_pais_query_dialog_active = NULL;
996 g_hostname = ::wxGetHostName();
997 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
999 androidGetDeviceInfo();
1000 g_hostname = wxString(
"Android-") + g_android_Device_Model;
1001 g_hostname.Replace(
" ",
"-",
true);
1006 wxString p(
"Portable-");
1007 g_hostname = p + g_hostname;
1012 pLayerList =
new LayerList;
1017 auto &navobj_db = NavObj_dB::GetInstance();
1024#ifdef PROBE_PORTS__WITH_HELPER
1025 user_user_id = getuid();
1026 file_user_id = geteuid();
1030 bool b_initial_load =
false;
1032 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
1033 if (config_test_file_name.FileExists())
1034 wxLogMessage(
"Using existing Config_File: " +
1035 g_Platform->GetConfigFileName());
1038 wxLogMessage(
"Creating new Config_File: " +
1039 g_Platform->GetConfigFileName());
1041 b_initial_load =
true;
1044 config_test_file_name.DirExists(config_test_file_name.GetPath()))
1045 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
1046 wxLogMessage(
"Cannot create config file directory for " +
1047 g_Platform->GetConfigFileName());
1052 pConfig = g_Platform->GetConfigObject();
1056 if (g_kiosk_startup) {
1058 g_wallpaper->ShowFullScreen(
true);
1059 g_wallpaper->Show();
1064 if (b_initial_load) g_Platform->SetDefaultOptions();
1066 g_Platform->applyExpertMode(g_bUIexpert);
1071 g_StyleManager->SetStyle(
"MUI_flat");
1072 if (!g_StyleManager->IsOK()) {
1073 wxString msg = _(
"Failed to initialize the user interface. ");
1074 msg << _(
"OpenCPN cannot start. ");
1075 msg << _(
"The necessary configuration files were not found. ");
1076 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
1077 << _(
" for details.") <<
"\n\n";
1078 msg << g_Platform->GetSharedDataDir();
1080 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
1081 wxCANCEL | wxICON_ERROR);
1088 if (style) style->chartStatusWindowTransparent =
true;
1092 pWayPointMan = NULL;
1096 msg.Printf(
"Detected display size (horizontal): %d mm",
1101 if (g_config_display_size_manual &&
1106 msg.Printf(
"Display size (horizontal) config override: %d mm",
1115 int SelectPixelRadius = 50;
1117 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1118 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1119 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1123 if (!n_NavMessageShown) {
1130#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1133 g_Platform->SetLocaleSearchPrefixes();
1135 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1137 imsg =
"System default Language: " + def_lang_canonical;
1140 wxString cflmsg =
"Config file language: " + g_locale;
1141 wxLogMessage(cflmsg);
1143 if (g_locale.IsEmpty()) {
1144 g_locale = def_lang_canonical;
1145 cflmsg =
"Config file language empty, using system default: " + g_locale;
1146 wxLogMessage(cflmsg);
1150 g_locale = g_Platform->GetAdjustedAppLocale();
1151 cflmsg =
"Adjusted App language: " + g_locale;
1152 wxLogMessage(cflmsg);
1155 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1157 imsg =
"Opencpn language set to: ";
1164 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1166 wxLogMessage(
"wxLocale support not available");
1171 if (g_config_wizard || b_initial_load) {
1173 auto res = wiz.Run();
1184 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1185 g_bUpgradeInProcess = (vs != g_config_version_string);
1187 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1190 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1191 wxLogMessage(g_Platform->GetLargeLogMessage());
1196 g_bdisable_opengl =
true;
1199 if (g_bdisable_opengl) g_bopengl =
false;
1201#if defined(__linux__) && !defined(__ANDROID__)
1202 if (g_bSoftwareGL) {
1203 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1216 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1218 wxMin(g_memCacheLimit, 1024 * 1024);
1224 g_memCacheLimit = 0;
1225 if (0 == g_nCacheLimit)
1226 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1231 "chartlist.dat",
"CHRTLIST.DAT");
1235 "mmsitoname.csv",
"MMSINAME.CSV");
1238 if (pInit_Chart_Dir->IsEmpty()) {
1239 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1243 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1245 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1249 InitRestListeners();
1250 new_msg_type_listener.
Init(NavMsgBus::GetInstance().new_msg_event,
1254 gDefaultWorldMapLocation =
"gshhs";
1255 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1256 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1257 if (gWorldMapLocation == wxEmptyString) {
1258 gWorldMapLocation = gDefaultWorldMapLocation;
1263 wxString default_tcdata0 =
1264 (g_Platform->GetSharedDataDir() +
"tcdata" +
1265 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1266 wxString default_tcdata1 =
1267 (g_Platform->GetSharedDataDir() +
"tcdata" +
1268 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1269 wxString default_tcdata2 =
1270 (g_Platform->GetSharedDataDir() +
"tcdata" +
1271 wxFileName::GetPathSeparator() +
"ticon-europe-global.tcd");
1273 if (TideCurrentDataSet.empty()) {
1274 TideCurrentDataSet.push_back(
1275 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1276 TideCurrentDataSet.push_back(
1277 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1278 TideCurrentDataSet.push_back(
1279 g_Platform->NormalizePath(default_tcdata2).ToStdString());
1284 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1285 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1286 wxFileName::GetPathSeparator() +
"2bells.wav");
1287 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1292 g_Platform->Initialize_2();
1294 LoadChartDatabase();
1298 g_kiosk_startup =
false;
1302 if (!g_kiosk_startup) {
1304 SetTopWindow(gFrame);
1311 OCPNPlatform::Initialize_4();
1314 androidHideBusyIcon();
1317 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1321 if (!g_kiosk_startup) {
1322 if (!DoNavMessage(vs)) {
1329 g_bHasHwClock =
true;
1330#if defined(__UNIX__) && !defined(__ANDROID__)
1333 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1334 (stat(
"/dev/misc/rtc", &buffer) == 0));
1337 g_config_version_string = vs;
1342 for (
auto *cp : TheConnectionParams()) {
1344 if (cp->GetDSPort().Contains(
"Serial")) {
1345 std::string port(cp->Port.ToStdString());
1352 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1355 if (ipv4_addrs.size()) {
1356 std::string ipAddr = ipv4_addrs[0];
1359 if (data_dir.Last() != wxFileName::GetPathSeparator())
1360 data_dir.Append(wxFileName::GetPathSeparator());
1362 make_certificate(ipAddr, data_dir.ToStdString());
1364 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1365 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1369 if (!g_kiosk_startup) {
1373 wxLogMessage(
"InitTimer start");
1374 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1384 CallAfter([
this]() {
1386 g_wallpaper->Show(
false);
1388 g_bFullscreen =
true;
1391 g_wallpaper->Destroy();
1392 g_wallpaper =
nullptr;
1394 SetTopWindow(gFrame);
1398 wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1399 if (!DoNavMessage(vs)) {
1405 wxLogMessage(
"InitTimer start");
1406 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1411void MyApp::BuildMainFrame() {
1414 wxSize new_frame_size(-1, -1);
1416 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1418 user_colors::Initialize();
1420 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1421 (g_nframewin_y <= ch))
1422 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1424 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1430 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1431 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1432 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1433 g_bframemax =
false;
1436 g_lastClientRectx = cx;
1437 g_lastClientRecty = cy;
1438 g_lastClientRectw = cw;
1439 g_lastClientRecth = ch;
1442 wxPoint position(0, 0);
1443 wxSize dsize = wxGetDisplaySize();
1446 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1449 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1450 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1455 frame_rect.left = position.x;
1456 frame_rect.top = position.y;
1457 frame_rect.right = position.x + new_frame_size.x;
1458 frame_rect.bottom = position.y + new_frame_size.y;
1462 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1463 position = wxPoint(10, 10);
1468 const wxPoint ptScreen(position.x, position.y);
1469 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1471 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1474 g_nframewin_posx = position.x;
1475 g_nframewin_posy = position.y;
1478 wxSize asz = getAndroidDisplayDimensions();
1483 if ((cw > 200) && (ch > 200))
1484 new_frame_size.Set(cw, ch);
1486 new_frame_size.Set(800, 400);
1492 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1493 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1496 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1497 myframe_window_title += g_Platform->GetHomeDir();
1498 myframe_window_title +=
"]";
1502 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1503 new_frame_size.x, new_frame_size.y, position.x, position.y);
1507 auto dockart =
new wxAuiDefaultDockArt;
1510 gFrame =
new MyFrame(myframe_window_title, position, new_frame_size,
1511 m_rest_server, dockart,
1512 [&](
const std::string &path) {
return OpenFile(path); });
1517 g_pauimgr->SetDockSizeConstraint(.9, .9);
1523 g_Platform->Initialize_3();
1525 gFrame->CreateCanvasLayout();
1527 gFrame->SetGPSCompassScale();
1531 gFrame->SetChartUpdatePeriod();
1535 gFrame->ApplyGlobalSettings(
false);
1536 gFrame->SetAllToolbarScale();
1537 gFrame->SetAndApplyColorScheme(global_color_scheme);
1538 if (g_bframemax) gFrame->Maximize(
true);
1541 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->
GetPixPerMM() > 4.0))
1542 gFrame->Maximize(
true);
1551 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1552 g_GLOptions.m_bTextureCompressionCaching) {
1553 gFrame->ReloadAllVP();
1572 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1576 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1577 wxLogMessage(dogmsg);
1579 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1587 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1592 gFrame->DoChartUpdate();
1594 CommBridge::GetInstance();
1597 for (
auto *cp : TheConnectionParams()) {
1600 cp->b_IsSetup = TRUE;
1607 auto style = g_StyleManager->GetCurrentStyle();
1608 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1610 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1612 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1614 AbstractPlatform::ShowBusySpinner();
1616 AbstractPlatform::HideBusySpinner();
1620 wxString perspective;
1622 pConfig->Read(
"AUIPerspective", &perspective);
1629 bool bno_load =
false;
1631 wxArrayString name_array;
1632 wxStringTokenizer st(perspective,
"|;");
1633 while (st.HasMoreTokens()) {
1634 wxString s1 = st.GetNextToken();
1635 if (s1.StartsWith(
"name=")) {
1636 wxString sc = s1.AfterFirst(
'=');
1641 wxAuiPaneInfoArray pane_array_val =
g_pauimgr->GetAllPanes();
1642 for (
unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1643 wxAuiPaneInfo pane = pane_array_val.Item(i);
1647 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1653 if (!bno_load)
g_pauimgr->LoadPerspective(perspective,
false);
1658 for (
unsigned int i = 0; i <
g_canvasArray.GetCount(); i++) {
1661 wxSize frameSize = GetClientSize();
1662 wxSize minSize =
g_pauimgr->GetPane(cc).min_size;
1663 int width = wxMax(minSize.x, frameSize.x / 10);
1664 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1686 if (!g_bdisable_opengl) {
1689 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1690 gFrame->m_defer_size = gFrame->GetSize();
1691 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1693 gFrame->m_bdefer_resize =
true;
1703 glDeleteTextures(n, texts);
1712 gFrame->SetSize(getAndroidDisplayDimensions());
1713 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1725void MyApp::LoadChartDatabase() {
1727 ArrayOfCDI ChartDirArray;
1728 pConfig->LoadChartDirArray(ChartDirArray);
1733 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1736 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1737 if (RegKey.Exists()) {
1739 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1741 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1743 wxStringTokenizer tkz(dirs,
";");
1744 while (tkz.HasMoreTokens()) {
1745 wxString token = tkz.GetNextToken();
1748 cdi.fullpath = token.Trim();
1749 cdi.magic_number =
"";
1751 ChartDirArray.Add(cdi);
1758 cdi.fullpath =
"charts";
1759 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1760 cdi.magic_number =
"";
1761 ChartDirArray.Add(cdi);
1765 if (ndirs)
pConfig->UpdateChartDirs(ChartDirArray);
1775 if (!ChartDirArray.GetCount())
1776 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1783 g_restore_dbindex = 0;
1787 if (g_restore_dbindex >= 0) {
1788 if (
ChartData->GetChartTableEntries() == 0)
1789 g_restore_dbindex = -1;
1791 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1792 g_restore_dbindex = 0;
1800 wxLogMessage(
"opencpn::MyApp starting exit.");
1802 m_usb_watcher.Stop();
1805 wxDateTime lognow = wxDateTime::Now();
1807 wxString day = lognow.FormatISODate();
1808 wxString utc = lognow.FormatISOTime();
1809 wxString navmsg =
"LOGBOOK: ";
1817 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ",
gLat,
gLon);
1821 if (std::isnan(
gCog))
1822 cog.Printf(
"COG ----- ");
1824 cog.Printf(
"COG %10.5f ",
gCog);
1827 if (std::isnan(
gSog))
1828 sog.Printf(
"SOG ----- ");
1830 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(
gSog));
1837 data.Printf(
"OFF: Lat %10.5f Lon %10.5f",
gLat,
gLon);
1840 wxLogMessage(navmsg);
1841 g_loglast_time = lognow;
1859 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1868 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1869 wxLog::FlushActive();
1871 g_Platform->CloseLogFile();
1873 delete pInit_Chart_Dir;
1881 delete pWayPointMan;
1883 navutil::DeinitGlobals();
1885 user_colors::DeInitialize();
1892 delete g_StyleManager;
1897 void RestoreSystemColors();
1898 RestoreSystemColors();
1905#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1909 FontMgr::Shutdown();
1911 g_Platform->OnExit_2();
1918#ifdef LINUX_CRASHRPT
1919void MyApp::OnFatalException() { g_crashprint.Report(); }
1925void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1930 if (eErrClass == CE_Debug)
1931 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1932 else if (eErrClass == CE_Warning)
1933 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1935 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1937 wxString str(msg, wxConvUTF8);
Select * pSelectAIS
Global instance.
wxString AISTargetNameFileName
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetListDialog.
Class AISTargetQueryDialog.
Chart canvas configuration state
Purpose: TLS Certificate support.
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
arrayofCanvasPtr g_canvasArray
Global instance.
Generic Chart canvas base.
EventVar reverse_route
Notified with a string GUID when user wants to reverse a route.
EventVar activate_route
Notified with a string GUID when user wants to activate a route.
A modal message dialog with confirmation button and cancel button.
ChartCanvas - Main chart display and interaction component.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
Manages the chart database and provides access to chart data.
bool LoadBinary(const wxString &filename, ArrayOfCDI &dir_array_check)
Load the chart database from a binary file.
void Notify() override
Notify all listeners, no data supplied.
static void SeedRandom()
Seed the random generator used by GetUUID().
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
Unstable development API.
EventType
Reported events bitmask.
Common interface for all instance checkers.
virtual bool IsMainInstance()=0
Return true if this process is the primary opencpn instance.
virtual void CleanUp()
Remove all persistent instance state, including possible lock file and defunct opencpn processes.
virtual void OnExit()
Do whatever needed before wxWidget's checks triggers.
virtual void WaitUntilValid()
Wait until this object can be used for example for Dbus connection.
static LocalServerApi & GetInstance()
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
Custom event class for OpenCPN's notification system.
bool LoadAllPlugIns(bool enabled_plugins, bool keep_orphans=false)
Update catalog with imported metadata and load all plugin library files.
bool StartServer(const fs::path &certificate_location) override
Start the server thread.
Represents a waypoint or mark within the navigation system.
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
wxString m_RouteNameString
User-assigned name for the route.
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Window for displaying chart thumbnails.
Represents a track, which is a series of connected track points.
Listen to hardware events and notifies SystemEvents when new devices are plugged in.
OpenGL chart rendering canvas.
Handles crash reporting in wxWidgets applications.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
CommBridge class and helpers.
void MakeLoopbackDriver()
Create and register the loopback driver.
void MakeInternalDriver()
Create and register the internal driver.
void MakeCommDriver(const ConnectionParams *params)
Create and register a driver for given connection.
Communication drivers factory and support.
NMEA Data Multiplexer Object.
Variables maintained by comm stack, read-only access for others.
Primary navigation console display for route and vessel tracking.
Config file user configuration interface.
std::vector< size_t > g_config_display_size_mm
Size of pysical screen in millimeters.
double g_display_size_mm
Physical display width (mm)
Global variables stored in configuration file.
Dump debug info on crash.
Chart display details slider.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
Misc GUI event vars, a singleton.
size_t g_current_monitor
Current monitor displaying main application frame.
int g_NeedDBUpdate
0 - No update needed, 1 - Update needed because there is no chart database, inform user 2 - Start upd...
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Instance check interface.
The local API has a server side handling commands and a client part issuing commands.
Enhanced logging interface on top of wx/log.h.
MacOS hardware probing functions.
Waypoint properties maintenance dialog.
Start/stop mdns service routines.
Multiplexer class and helpers.
void check_last_start()
Check if the last start failed, possibly invoke user dialog and set safe mode state.
void clear_check()
Mark last run as successful.
MySQL based storage for routes, tracks, etc.
MyConfig * pConfig
Global instance.
Navigation Utility Functions without GUI dependencies.
User notifications manager.
s57RegistrarMgr * m_pRegistrarMan
Global instance.
General observable implementation with several specializations.
OCPN_AUIManager * g_pauimgr
Global instance.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Plugin remote repositories installation and Uninstall/list operations.
PlugInManager * g_pi_manager
Global instance.
RoutePoint * pAnchorWatchPoint2
Global instance.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
RoutePoint * pAnchorWatchPoint1
Global instance.
RouteManagerDialog * pRouteManagerDialog
Global instance.
S57 object query result window.
Select * pSelect
Global instance.
Select * pSelectTC
Global instance.
Selected route, segment, waypoint, etc.
SENCThreadManager * g_SencThreadManager
Global instance.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
Access checks for comm devices and dongle.