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/listctrl.h>
105#include <wx/printdlg.h>
107#include <wx/progdlg.h>
108#include <wx/settings.h>
109#include <wx/stdpaths.h>
110#include <wx/tokenzr.h>
113#include "o_sound/o_sound.h"
133#include "model/nav_object_database.h"
145#include "ais_info_gui.h"
159#include "gdal/cpl_csv.h"
172#include "route_ctx_factory.h"
179#include "safe_mode_gui.h"
180#include "std_filesystem.h"
186#include "user_colors.h"
199void RedirectIOToConsole();
211#include "androidUTIL.h"
216using namespace std::literals::chrono_literals;
218const char *
const kUsage =
221 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
222 opencpn --remote [-R] | -q] | -e] |-o <str>]
224Options for starting opencpn
226 -c, --configdir=<dirpath> Use alternative configuration directory.
227 -p, --portable Run in portable mode.
228 -f, --fullscreen Switch to full screen mode on start.
229 -G, --no_opengl Disable OpenGL video acceleration. This setting will
231 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
232 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
233 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
234 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
235 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
236 Zero or negative <num> specifies no limit.
238 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
239 -W, --config_wizard Start with initial configuration wizard
241Options manipulating already started opencpn
242 -r, --remote Execute commands on already running instance
243 -R, --raise Make running OpenCPN visible if hidden
244 -q, --quit Terminate already running opencpn
245 -e, --get_rest_endpoint Print rest server endpoint and exit.
246 -o, --open=<GPX file> Open file in running opencpn
249 GPX file GPX-formatted file with waypoints or routes.
253wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
254wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
256wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
257wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
258wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
259wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
260wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
261wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
262wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
263wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
264wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
272WX_DEFINE_OBJARRAY(ArrayOfCDI);
276static int user_user_id;
277static int file_user_id;
279static int g_mem_total, g_mem_initial;
281static unsigned int malloc_max;
283static int osMajor, osMinor;
285static bool g_bHasHwClock;
287static wxStopWatch init_sw;
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)
316 : wxFrame(
nullptr, wxID_ANY,
"Loading...", wxDefaultPosition,
317 wxSize(2000, 2000), wxSTAY_ON_TOP) {
319 SetBackgroundColour(wxColour(0, 0, 0));
321 wxPanel *panel =
new wxPanel(
this, wxID_ANY);
324 panel->SetBackgroundColour(wxColour(0, 0, 0));
327 wxBoxSizer *sizer =
new wxBoxSizer(wxVERTICAL);
328 sizer->Add(panel, 1, wxEXPAND);
338 GtkWidget *widget =
reinterpret_cast<GtkWidget *
>(GetHandle());
340 gtk_widget_realize(widget);
341 GdkWindow *gdk = gtk_widget_get_window(widget);
343 gdk_window_set_override_redirect(gdk, 1);
351void appendOSDirSlash(wxString *pString);
353void InitializeUserColors();
354void DeInitializeUserColors();
355void SetSystemColors(ColorScheme cs);
357static bool LoadAllPlugIns(
bool load_enabled) {
358 g_Platform->ShowBusySpinner();
359 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
360 g_Platform->HideBusySpinner();
368#if defined(__WXGTK__) || defined(__WXQT__)
369#include "bitmaps/opencpn.xpm"
372static wxString newPrivateFileName(wxString,
const char *name,
373 [[maybe_unused]]
const char *windowsName) {
374 wxString fname = wxString::FromUTF8(name);
375 wxString filePathAndName;
378 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
379 filePathAndName.Append(wxFileName::GetPathSeparator());
382 wxString fwname = wxString::FromUTF8(windowsName);
383 filePathAndName.Append(fwname);
385 filePathAndName.Append(fname);
388 return filePathAndName;
391static bool DoNavMessage(wxString &new_version_string) {
396 if (!n_NavMessageShown || (new_version_string != g_config_version_string) ||
397 (g_AndroidVersionCode != androidGetVersionCode())) {
402 qDebug() <<
"Closing due to NavWarning Cancel";
408 n_NavMessageShown = 1;
412 g_AndroidVersionCode = androidGetVersionCode();
413 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
418 if (!n_NavMessageShown || (new_version_string != g_config_version_string)) {
420 n_NavMessageShown = 1;
427static void ActivateRoute(
const std::string &guid) {
430 wxLogMessage(
"Cannot activate guid: no such route");
441 point = route->GetPoint(2);
448static void ReverseRoute(
const std::string &guid) {
451 wxLogMessage(
"Cannot activate guid: no such route");
460static void ParseLoglevel(wxCmdLineParser &parser) {
461 wxLog::SetLogLevel(wxLOG_Message);
464static void ParseLoglevel(wxCmdLineParser &parser) {
465 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
466 strLevel = strLevel ? strLevel :
"info";
468 if (parser.Found(
"l", &wxLevel)) {
469 strLevel = wxLevel.c_str();
471 wxLogLevel level = OcpnLog::str2level(strLevel);
472 if (level == OcpnLog::LOG_BADLEVEL) {
473 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
476 wxLog::SetLogLevel(level);
480static void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
481 const char *pszErrorMsg) {
484 if (eErrClass == CE_Debug)
485 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
486 else if (eErrClass == CE_Warning)
487 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
489 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
491 wxString str(msg, wxConvUTF8);
501BEGIN_EVENT_TABLE(
MyApp, wxApp)
502EVT_ACTIVATE_APP(MyApp::OnActivateApp)
513 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
514 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
515 setenv(
"GDK_BACKEND",
"x11", 1);
519 "mesa_glthread",
"false",
525void MyApp::InitRestListeners() {
526 auto activate_route = [&](wxCommandEvent ev) {
527 auto guid = ev.GetString().ToStdString();
530 rest_activate_listener.Init(m_rest_server.
activate_route, activate_route);
531 auto reverse_route = [&](wxCommandEvent ev) {
532 auto guid = ev.GetString().ToStdString();
535 rest_reverse_listener.Init(m_rest_server.
reverse_route, reverse_route);
538void MyApp::OnUnhandledException() {
545 }
catch (std::exception &e) {
547 what.Printf(
"standard exception with message \"%s\"", e.what());
549 what.Printf(
"standard exception of type \"%s\" with message \"%s\"",
550 typeid(e).name(), e.what());
553 what =
"unknown exception";
555 wxMessageOutputBest().Printf(
556 "Unhandled %s; terminating %s.\n", what,
557 wxIsMainThread() ?
"the application" :
"the thread in which it happened");
560void MyApp::OnNewMsgTypes() {
561 for (
auto it : m_api_events_callbacks)
562 it.second(
HostApi122::EventType::kNewMessageType);
565void MyApp::RegisterApiEventCallback(
566 const std::string &plugin_name,
569 m_api_events_callbacks[plugin_name] = std::move(callback);
571 m_api_events_callbacks.erase(plugin_name);
574bool MyApp::OpenFile(
const std::string &path) {
576 auto result = nav_objects.load_file(path.c_str());
578 std::string s(_(
"Cannot load route or waypoint file: "));
579 s += std::string(
"\"") + path +
"\"";
580 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
586 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
590 LLBBox box = nav_objects.GetBBox();
591 if (box.GetValid()) {
592 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
598void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
601 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
602 parser.AddSwitch(
"p",
"portable");
603 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
604 wxCMD_LINE_PARAM_OPTIONAL);
605 parser.AddSwitch(
"f",
"fullscreen");
606 parser.AddSwitch(
"G",
"no_opengl");
607 parser.AddSwitch(
"W",
"config_wizard");
608 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
609 parser.AddSwitch(
"D",
"rebuild_chart_db");
610 parser.AddSwitch(
"P",
"parse_all_enc");
611 parser.AddOption(
"l",
"loglevel");
612 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
613 parser.AddSwitch(
"U",
"unit_test_2");
614 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
615 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
616 parser.AddSwitch(
"s",
"safe_mode");
617 parser.AddSwitch(
"r",
"remote");
618 parser.AddSwitch(
"R",
"raise");
619 parser.AddSwitch(
"q",
"quit");
620 parser.AddSwitch(
"e",
"get_rest_endpoint");
621 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
622 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
627bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
634bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
639 g_unit_test_2 = parser.Found(
"unit_test_2");
640 g_bportable = parser.Found(
"p");
641 g_start_fullscreen = parser.Found(
"fullscreen");
642 g_bdisable_opengl = parser.Found(
"no_opengl");
643 g_rebuild_gl_cache = parser.Found(
"rebuild_gl_raster_cache");
645 g_parse_all_enc = parser.Found(
"parse_all_enc");
646 g_config_wizard = parser.Found(
"config_wizard");
647 if (parser.Found(
"unit_test_1", &number)) {
648 g_unit_test_1 =
static_cast<int>(number);
649 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
651 safe_mode::SetMode(parser.Found(
"safe_mode"));
652 ParseLoglevel(parser);
654 if (parser.Found(
"configdir", &wxstr)) {
655 g_configdir = wxstr.ToStdString();
656 fs::path path(g_configdir);
657 if (!fs::exists(path) || !fs::is_directory(path)) {
658 std::cerr << g_configdir <<
" is not an existing directory.\n";
663 bool has_start_options =
false;
664 static const std::vector<std::string> kStartOptions = {
669 "rebuild_gl_raster_cache",
675 for (
const auto &opt : kStartOptions) {
676 if (parser.Found(opt)) has_start_options =
true;
678 if (has_start_options && parser.Found(
"remote")) {
679 std::cerr <<
"this option is not compatible with --remote\n";
683 bool has_remote_options =
false;
684 static const std::vector<std::string> kRemoteOptions = {
685 "raise",
"quit",
"open",
"get_rest_endpoint"};
686 for (
const auto &opt : kRemoteOptions) {
687 if (parser.Found(opt)) has_remote_options =
true;
689 if (has_remote_options && !parser.Found(
"remote")) {
690 std::cerr <<
"This option requires --remote\n";
694 for (
size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
695 g_params.push_back(parser.GetParam(paramNr).ToStdString());
698 if (!parser.Found(
"remote"))
699 m_parsed_cmdline = ParsedCmdline();
700 else if (parser.Found(
"raise"))
701 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
702 else if (parser.Found(
"quit"))
703 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
704 else if (parser.Found(
"get_rest_endpoint"))
705 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
706 else if (parser.Found(
"open", &optarg))
707 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
708 else if (parser.GetParamCount() == 1)
710 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
711 else if (!has_start_options && !has_remote_options) {
713 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
723bool MyApp::OnExceptionInMainLoop() {
724 wxLogWarning(
"Caught MainLoopException, continuing...");
729void MyApp::OnActivateApp(wxActivateEvent &event) {
return; }
732 if (m_exitcode != -2)
return m_exitcode;
733 return wxAppConsole::OnRun();
737 if (!wxApp::OnInit())
return false;
740 androidEnableBackButton(
false);
741 androidEnableOptionItems(
false);
746#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
752 wxBitmap bmp(10, 10, -1);
754 dc.SelectObject(bmp);
755 dc.DrawText(
"X", 0, 0);
770 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
774 std::cerr <<
"No remote opencpn found. Giving up.\n";
779 std::unique_ptr<LocalClientApi> client;
781 client = LocalClientApi::GetClient();
783 WARNING_LOG <<
"Ipc client exception: " << ie.str();
790 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
791 "to respond.\nPlease retry."),
792 "OpenCPN", wxICON_INFORMATION | wxOK);
797 auto result = client->HandleCmdline(m_parsed_cmdline.action,
798 m_parsed_cmdline.arg);
802 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
811 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
812 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
818 safe_mode::CheckLastStart();
823 OCPNPlatform::Initialize_1();
828 MyApp::SetAppDisplayName(
"OpenCPN");
831 wxDateTime x = wxDateTime::UNow();
832 long seed = x.GetMillisecond();
833 seed *= x.GetTicks();
838 setlocale(LC_NUMERIC,
"C");
840 g_start_time = wxDateTime::Now();
842 g_loglast_time = g_start_time;
843 g_loglast_time.MakeGMT();
844 g_loglast_time.Subtract(
845 wxTimeSpan(0, 29, 0, 0));
847 AnchorPointMinDist = 5.0;
853 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
857 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
858 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
859 wxFONTENCODING_SYSTEM);
860 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
863 auto ¬eman = NotificationManager::GetInstance();
864 noteman.ScrubNotificationDirectory(30);
867 if (!g_Platform->InitializeLogFile()) {
879 wxLogMessage(
"\n\n________\n");
881 wxDateTime now = wxDateTime::Now();
882 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
883 now.FormatISODate().mb_str().data());
884 wxLogLevel level = wxLog::GetLogLevel();
885 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
887 wxString wxver(wxVERSION_STRING);
888 wxver.Prepend(
"wxWidgets version: ");
890 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
894 os_name = platforminfo.GetOperatingSystemIdName();
896 os_name = platforminfo.GetOperatingSystemFamilyName();
899 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
900 platforminfo.GetPortIdName();
902 wxLogMessage(wxver +
" " + platform);
904 ::wxGetOsVersion(&osMajor, &osMinor);
905 wxString osVersionMsg;
906 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
907 wxLogMessage(osVersionMsg);
909 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
910 g_mem_total / 1024, g_mem_initial / 1024);
915 if (!detail->osd_names_like.empty())
916 like0 = detail->osd_names_like[0].c_str();
917 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
918 detail->osd_arch.c_str(), detail->osd_name.c_str(),
919 detail->osd_version.c_str(), detail->osd_ID.c_str(),
921 wxLogMessage(msgplat);
923 wxString imsg =
"SData_Locn is ";
924 imsg += g_Platform->GetSharedDataDir();
928 ::wxInitAllImageHandlers();
932 prepareAndroidStyleSheets();
936 pInit_Chart_Dir =
new wxString();
941 imsg =
"PrivateDataDir is ";
947 navutil::InitGlobals();
951 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
955 pSelect->SetSelectPixelRadius(12);
968 g_pais_query_dialog_active = NULL;
971 g_hostname = ::wxGetHostName();
972 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
974 androidGetDeviceInfo();
975 g_hostname = wxString(
"Android-") + g_android_Device_Model;
976 g_hostname.Replace(
" ",
"-",
true);
981 wxString p(
"Portable-");
982 g_hostname = p + g_hostname;
987 pLayerList =
new LayerList;
992 auto &navobj_db = NavObj_dB::GetInstance();
999#ifdef PROBE_PORTS__WITH_HELPER
1000 user_user_id = getuid();
1001 file_user_id = geteuid();
1005 bool b_initial_load =
false;
1007 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
1008 if (config_test_file_name.FileExists())
1009 wxLogMessage(
"Using existing Config_File: " +
1010 g_Platform->GetConfigFileName());
1013 wxLogMessage(
"Creating new Config_File: " +
1014 g_Platform->GetConfigFileName());
1016 b_initial_load =
true;
1019 config_test_file_name.DirExists(config_test_file_name.GetPath()))
1020 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
1021 wxLogMessage(
"Cannot create config file directory for " +
1022 g_Platform->GetConfigFileName());
1027 pConfig = g_Platform->GetConfigObject();
1031 if (g_kiosk_startup) {
1033 g_wallpaper->ShowFullScreen(
true);
1034 g_wallpaper->Show();
1039 if (b_initial_load) g_Platform->SetDefaultOptions();
1041 g_Platform->applyExpertMode(g_bUIexpert);
1046 g_StyleManager->SetStyle(
"MUI_flat");
1047 if (!g_StyleManager->IsOK()) {
1048 wxString msg = _(
"Failed to initialize the user interface. ");
1049 msg << _(
"OpenCPN cannot start. ");
1050 msg << _(
"The necessary configuration files were not found. ");
1051 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
1052 << _(
" for details.") <<
"\n\n";
1053 msg << g_Platform->GetSharedDataDir();
1055 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
1056 wxCANCEL | wxICON_ERROR);
1063 if (style) style->chartStatusWindowTransparent =
true;
1067 pWayPointMan = NULL;
1071 msg.Printf(
"Detected display size (horizontal): %d mm",
1076 if (g_config_display_size_manual &&
1081 msg.Printf(
"Display size (horizontal) config override: %d mm",
1090 int SelectPixelRadius = 50;
1092 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1093 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1094 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1098 if (!n_NavMessageShown) {
1105#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1108 g_Platform->SetLocaleSearchPrefixes();
1110 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1112 imsg =
"System default Language: " + def_lang_canonical;
1115 wxString cflmsg =
"Config file language: " + g_locale;
1116 wxLogMessage(cflmsg);
1118 if (g_locale.IsEmpty()) {
1119 g_locale = def_lang_canonical;
1120 cflmsg =
"Config file language empty, using system default: " + g_locale;
1121 wxLogMessage(cflmsg);
1125 g_locale = g_Platform->GetAdjustedAppLocale();
1126 cflmsg =
"Adjusted App language: " + g_locale;
1127 wxLogMessage(cflmsg);
1130 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1132 imsg =
"Opencpn language set to: ";
1139 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1141 wxLogMessage(
"wxLocale support not available");
1146 if (g_config_wizard || b_initial_load) {
1148 auto res = wiz.Run();
1159 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1160 g_bUpgradeInProcess = (vs != g_config_version_string);
1162 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1165 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1166 wxLogMessage(g_Platform->GetLargeLogMessage());
1171 g_bdisable_opengl =
true;
1174 if (g_bdisable_opengl) g_bopengl =
false;
1176#if defined(__linux__) && !defined(__ANDROID__)
1177 if (g_bSoftwareGL) {
1178 setenv(
"LIBGL_ALWAYS_SOFTWARE",
"1", 1);
1191 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1193 wxMin(g_memCacheLimit, 1024 * 1024);
1199 g_memCacheLimit = 0;
1200 if (0 == g_nCacheLimit)
1201 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1206 "chartlist.dat",
"CHRTLIST.DAT");
1210 "mmsitoname.csv",
"MMSINAME.CSV");
1213 if (pInit_Chart_Dir->IsEmpty()) {
1214 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1218 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1220 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1224 InitRestListeners();
1225 new_msg_type_listener.Init(NavMsgBus::GetInstance().new_msg_event,
1229 gDefaultWorldMapLocation =
"gshhs";
1230 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1231 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1232 if (gWorldMapLocation == wxEmptyString) {
1233 gWorldMapLocation = gDefaultWorldMapLocation;
1238 wxString default_tcdata0 =
1239 (g_Platform->GetSharedDataDir() +
"tcdata" +
1240 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1241 wxString default_tcdata1 =
1242 (g_Platform->GetSharedDataDir() +
"tcdata" +
1243 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1244 wxString default_tcdata2 =
1245 (g_Platform->GetSharedDataDir() +
"tcdata" +
1246 wxFileName::GetPathSeparator() +
"ticon-europe-global.tcd");
1248 if (TideCurrentDataSet.empty()) {
1249 TideCurrentDataSet.push_back(
1250 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1251 TideCurrentDataSet.push_back(
1252 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1253 TideCurrentDataSet.push_back(
1254 g_Platform->NormalizePath(default_tcdata2).ToStdString());
1259 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1260 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1261 wxFileName::GetPathSeparator() +
"2bells.wav");
1262 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1267 g_Platform->Initialize_2();
1269 LoadChartDatabase();
1273 g_kiosk_startup =
false;
1277 if (!g_kiosk_startup) {
1279 SetTopWindow(gFrame);
1286 OCPNPlatform::Initialize_4();
1289 androidHideBusyIcon();
1292 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1296 if (!g_kiosk_startup) {
1297 if (!DoNavMessage(vs)) {
1304 g_bHasHwClock =
true;
1305#if defined(__UNIX__) && !defined(__ANDROID__)
1308 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1309 (stat(
"/dev/misc/rtc", &buffer) == 0));
1312 g_config_version_string = vs;
1318 if (cp->is_enabled) {
1319 if (cp->GetDSPort().Contains(
"Serial")) {
1320 std::string port(cp->serial_port.ToStdString());
1327 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1330 if (ipv4_addrs.size()) {
1331 std::string ipAddr = ipv4_addrs[0];
1334 if (data_dir.Last() != wxFileName::GetPathSeparator())
1335 data_dir.Append(wxFileName::GetPathSeparator());
1337 make_certificate(ipAddr, data_dir.ToStdString());
1339 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1340 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1344 if (!g_kiosk_startup) {
1348 wxLogMessage(
"InitTimer start");
1349 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1359 CallAfter([
this]() {
1361 g_wallpaper->Show(
false);
1363 g_bFullscreen =
true;
1366 g_wallpaper->Destroy();
1367 g_wallpaper =
nullptr;
1369 SetTopWindow(gFrame);
1373 wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1374 if (!DoNavMessage(vs)) {
1380 wxLogMessage(
"InitTimer start");
1381 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1386void MyApp::BuildMainFrame() {
1389 wxSize new_frame_size(-1, -1);
1391 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1393 user_colors::Initialize();
1395 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1396 (g_nframewin_y <= ch))
1397 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1399 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1405 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1406 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1407 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1408 g_bframemax =
false;
1411 g_lastClientRectx = cx;
1412 g_lastClientRecty = cy;
1413 g_lastClientRectw = cw;
1414 g_lastClientRecth = ch;
1417 wxPoint position(0, 0);
1418 wxSize dsize = wxGetDisplaySize();
1421 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1424 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1425 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1430 frame_rect.left = position.x;
1431 frame_rect.top = position.y;
1432 frame_rect.right = position.x + new_frame_size.x;
1433 frame_rect.bottom = position.y + new_frame_size.y;
1437 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1438 position = wxPoint(10, 10);
1443 const wxPoint ptScreen(position.x, position.y);
1444 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1446 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1449 g_nframewin_posx = position.x;
1450 g_nframewin_posy = position.y;
1453 wxSize asz = getAndroidDisplayDimensions();
1458 if ((cw > 200) && (ch > 200))
1459 new_frame_size.Set(cw, ch);
1461 new_frame_size.Set(800, 400);
1467 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1468 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1471 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1472 myframe_window_title += g_Platform->GetHomeDir();
1473 myframe_window_title +=
"]";
1477 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1478 new_frame_size.x, new_frame_size.y, position.x, position.y);
1482 auto dockart =
new wxAuiDefaultDockArt;
1485 gFrame =
new MyFrame(myframe_window_title, position, new_frame_size,
1486 m_rest_server, dockart,
1487 [&](
const std::string &path) {
return OpenFile(path); });
1492 g_pauimgr->SetDockSizeConstraint(.9, .9);
1498 g_Platform->Initialize_3();
1500 gFrame->CreateCanvasLayout();
1502 gFrame->SetGPSCompassScale();
1506 gFrame->SetChartUpdatePeriod();
1510 gFrame->ApplyGlobalSettings(
false);
1511 gFrame->SetAllToolbarScale();
1512 gFrame->SetAndApplyColorScheme(global_color_scheme);
1513 if (g_bframemax) gFrame->Maximize(
true);
1516 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->
GetPixPerMM() > 4.0))
1517 gFrame->Maximize(
true);
1526 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1527 g_GLOptions.m_bTextureCompressionCaching) {
1528 gFrame->ReloadAllVP();
1547 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1551 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1552 wxLogMessage(dogmsg);
1554 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1562 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1567 gFrame->DoChartUpdate();
1569 CommBridge::GetInstance();
1573 if (cp->is_enabled) {
1575 cp->is_setup = TRUE;
1582 auto style = g_StyleManager->GetCurrentStyle();
1583 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1585 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1587 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1589 AbstractPlatform::ShowBusySpinner();
1591 AbstractPlatform::HideBusySpinner();
1595 wxString perspective;
1597 pConfig->Read(
"AUIPerspective", &perspective);
1604 bool bno_load =
false;
1606 wxArrayString name_array;
1607 wxStringTokenizer st(perspective,
"|;");
1608 while (st.HasMoreTokens()) {
1609 wxString s1 = st.GetNextToken();
1610 if (s1.StartsWith(
"name=")) {
1611 wxString sc = s1.AfterFirst(
'=');
1616 wxAuiPaneInfoArray pane_array_val =
g_pauimgr->GetAllPanes();
1617 for (
unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1618 wxAuiPaneInfo pane = pane_array_val.Item(i);
1622 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1628 if (!bno_load)
g_pauimgr->LoadPerspective(perspective,
false);
1633 for (
unsigned int i = 0; i <
g_canvasArray.GetCount(); i++) {
1636 wxSize frameSize = GetClientSize();
1637 wxSize minSize =
g_pauimgr->GetPane(cc).min_size;
1638 int width = wxMax(minSize.x, frameSize.x / 10);
1639 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1661 if (!g_bdisable_opengl) {
1664 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1665 gFrame->m_defer_size = gFrame->GetSize();
1666 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1668 gFrame->m_bdefer_resize =
true;
1678 glDeleteTextures(n, texts);
1687 gFrame->SetSize(getAndroidDisplayDimensions());
1688 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1700void MyApp::LoadChartDatabase() {
1702 ArrayOfCDI ChartDirArray;
1703 pConfig->LoadChartDirArray(ChartDirArray);
1708 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1711 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1712 if (RegKey.Exists()) {
1714 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1716 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1718 wxStringTokenizer tkz(dirs,
";");
1719 while (tkz.HasMoreTokens()) {
1720 wxString token = tkz.GetNextToken();
1723 cdi.fullpath = token.Trim();
1724 cdi.magic_number =
"";
1726 ChartDirArray.Add(cdi);
1733 cdi.fullpath =
"charts";
1734 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1735 cdi.magic_number =
"";
1736 ChartDirArray.Add(cdi);
1740 if (ndirs)
pConfig->UpdateChartDirs(ChartDirArray);
1750 if (!ChartDirArray.GetCount())
1751 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1758 g_restore_dbindex = 0;
1762 if (g_restore_dbindex >= 0) {
1763 if (
ChartData->GetChartTableEntries() == 0)
1764 g_restore_dbindex = -1;
1766 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1767 g_restore_dbindex = 0;
1775 wxLogMessage(
"opencpn::MyApp starting exit.");
1777 m_usb_watcher.Stop();
1780 wxDateTime lognow = wxDateTime::Now();
1782 wxString day = lognow.FormatISODate();
1783 wxString utc = lognow.FormatISOTime();
1784 wxString navmsg =
"LOGBOOK: ";
1792 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ",
gLat,
gLon);
1796 if (std::isnan(
gCog))
1797 cog.Printf(
"COG ----- ");
1799 cog.Printf(
"COG %10.5f ",
gCog);
1802 if (std::isnan(
gSog))
1803 sog.Printf(
"SOG ----- ");
1805 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(
gSog));
1812 data.Printf(
"OFF: Lat %10.5f Lon %10.5f",
gLat,
gLon);
1815 wxLogMessage(navmsg);
1816 g_loglast_time = lognow;
1834 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1843 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1844 wxLog::FlushActive();
1846 g_Platform->CloseLogFile();
1848 delete pInit_Chart_Dir;
1856 delete pWayPointMan;
1858 navutil::DeinitGlobals();
1860 user_colors::DeInitialize();
1867 delete g_StyleManager;
1872 void RestoreSystemColors();
1873 RestoreSystemColors();
1880#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1884 FontMgr::Shutdown();
1886 g_Platform->OnExit_2();
1893#ifdef LINUX_CRASHRPT
1894void MyApp::OnFatalException() { g_crashprint.Report(); }
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.
obs::EventVar reverse_route
Notified with a string GUID when user wants to reverse a route.
obs::EventVar activate_route
Notified with a string GUID when user wants to activate a route.
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.
static void SeedRandom()
Seed the random generator used by GetUUID().
obs::EventVar on_routes_update
Notified when list of routes is updated (no data in event)
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()
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.
void Notify() override
Notify all listeners, no data supplied.
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.
std::vector< ConnectionParams * > & TheConnectionParams()
Return global list of connections.
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 MarkStartAsOk()
Mark last run as successful.
bool GetMode()
Return true if we are running in safe mode.
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 pattern implementation built on top of wxWidgets event handling.
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.
bool ShowNavWarning(wxWindow *parent)
Show the "Welcome to OpenCPN" dialog.