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>
112#include "observable/observable.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"
173#include "route_ctx_factory.h"
180#include "safe_mode_gui.h"
181#include "std_filesystem.h"
187#include "user_colors.h"
200void RedirectIOToConsole();
212#include "androidUTIL.h"
217using namespace std::literals::chrono_literals;
219const char *
const kUsage =
222 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
223 opencpn --remote [-R] | -q] | -e] |-o <str>]
225Options for starting opencpn
227 -c, --configdir=<dirpath> Use alternative configuration directory.
228 -p, --portable Run in portable mode.
229 -f, --fullscreen Switch to full screen mode on start.
230 -G, --no_opengl Disable OpenGL video acceleration. This setting will
232 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
233 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
234 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
235 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
236 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
237 Zero or negative <num> specifies no limit.
239 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
240 -W, --config_wizard Start with initial configuration wizard
242Options manipulating already started opencpn
243 -r, --remote Execute commands on already running instance
244 -R, --raise Make running OpenCPN visible if hidden
245 -q, --quit Terminate already running opencpn
246 -e, --get_rest_endpoint Print rest server endpoint and exit.
247 -o, --open=<GPX file> Open file in running opencpn
250 GPX file GPX-formatted file with waypoints or routes.
254wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
255wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
257wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
258wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
259wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
260wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
261wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
262wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
263wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
264wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
265wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
275WX_DEFINE_OBJARRAY(ArrayOfCDI);
277static int user_user_id;
278static int file_user_id;
280static int g_mem_total, g_mem_initial;
282static unsigned int malloc_max;
284static int osMajor, osMinor;
286static bool g_bHasHwClock;
288#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
290wxLocale *plocale_def_lang = 0;
298extern sigjmp_buf env;
303DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
304 0x6b, 0xba, 0xe7, 0x22, 0xc0);
308static const long long lNaN = 0xfff8000000000000;
309#define NAN (*(double *)&lNaN)
313void appendOSDirSlash(wxString *pString);
315void InitializeUserColors();
316void DeInitializeUserColors();
317void SetSystemColors(ColorScheme cs);
319static bool LoadAllPlugIns(
bool load_enabled) {
320 g_Platform->ShowBusySpinner();
321 bool b = PluginLoader::GetInstance()->
LoadAllPlugIns(load_enabled);
322 g_Platform->HideBusySpinner();
330#if defined(__WXGTK__) || defined(__WXQT__)
331#include "bitmaps/opencpn.xpm"
334static wxString newPrivateFileName(wxString,
const char *name,
335 [[maybe_unused]]
const char *windowsName) {
336 wxString fname = wxString::FromUTF8(name);
337 wxString filePathAndName;
340 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
341 filePathAndName.Append(wxFileName::GetPathSeparator());
344 wxString fwname = wxString::FromUTF8(windowsName);
345 filePathAndName.Append(fwname);
347 filePathAndName.Append(fname);
350 return filePathAndName;
353void MyApp::OnNewMsgTypes() {
354 for (
auto it : m_api_events_callbacks)
355 it.second(
HostApi122::EventType::kNewMessageType);
358void MyApp::RegisterApiEventCallback(
359 const std::string &plugin_name,
362 m_api_events_callbacks[plugin_name] = std::move(callback);
364 m_api_events_callbacks.erase(plugin_name);
370 : wxFrame(
nullptr, wxID_ANY,
"Loading...", wxDefaultPosition,
371 wxSize(2000, 2000), wxSTAY_ON_TOP) {
373 SetBackgroundColour(wxColour(0, 0, 0));
375 wxPanel *panel =
new wxPanel(
this, wxID_ANY);
378 panel->SetBackgroundColour(wxColour(0, 0, 0));
381 wxBoxSizer *sizer =
new wxBoxSizer(wxVERTICAL);
382 sizer->Add(panel, 1, wxEXPAND);
392 GtkWidget *widget =
reinterpret_cast<GtkWidget *
>(GetHandle());
394 gtk_widget_realize(widget);
395 GdkWindow *gdk = gtk_widget_get_window(widget);
397 gdk_window_set_override_redirect(gdk, 1);
404bool ShowNavWarning() {
407OpenCPN is distributed in the hope that it will be useful, \
408but WITHOUT ANY WARRANTY; without even the implied \
409warranty of MERCHANTABILITY or FITNESS FOR A \
410PARTICULAR PURPOSE.\n\n\
411See the GNU General Public License for more details.\n\n\
412OpenCPN must only be used in conjunction with approved \
413paper charts and traditional methods of navigation.\n\n\
414DO NOT rely upon OpenCPN for safety of life or property.\n\n\
415Please click \"Agree\" and proceed, or \"Cancel\" to quit.\n"));
417 wxString vs = wxString::Format(
" .. Version %s", VERSION_FULL);
420 androidShowDisclaimer(_(
"OpenCPN for Android") + vs, msg);
423 msg.Replace(
"\n",
"<br>");
425 std::stringstream html;
426 html <<
"<html><body><p>";
427 html << msg.ToStdString();
428 html <<
"</p></body></html>";
430 std::string title = _(
"Welcome to OpenCPN").ToStdString();
431 std::string action = _(
"Agree").ToStdString();
433 info_dlg.SetInitialSize();
434 info_dlg.AddHtmlContent(html);
435 int agreed = info_dlg.ShowModal();
436 return agreed == wxID_OK;
440bool DoNavMessage(wxString &new_version_string) {
445 if (!n_NavMessageShown || (new_version_string != g_config_version_string) ||
446 (g_AndroidVersionCode != androidGetVersionCode())) {
450 if (!ShowNavWarning()) {
451 qDebug() <<
"Closing due to NavWarning Cancel";
457 n_NavMessageShown = 1;
461 g_AndroidVersionCode = androidGetVersionCode();
462 qDebug() <<
"Persisting Version Code: " << g_AndroidVersionCode;
467 if (!n_NavMessageShown || (new_version_string != g_config_version_string)) {
468 if (!ShowNavWarning())
return false;
469 n_NavMessageShown = 1;
482BEGIN_EVENT_TABLE(
MyApp, wxApp)
483EVT_ACTIVATE_APP(MyApp::OnActivateApp)
486static
void ActivateRoute(const std::
string &guid) {
489 wxLogMessage(
"Cannot activate guid: no such route");
500 point = route->GetPoint(2);
507static void ReverseRoute(
const std::string &guid) {
510 wxLogMessage(
"Cannot activate guid: no such route");
517void MyApp::InitRestListeners() {
518 auto activate_route = [&](wxCommandEvent ev) {
519 auto guid = ev.GetString().ToStdString();
522 rest_activate_listener.Init(m_rest_server.
activate_route, activate_route);
523 auto reverse_route = [&](wxCommandEvent ev) {
524 auto guid = ev.GetString().ToStdString();
527 rest_reverse_listener.Init(m_rest_server.
reverse_route, reverse_route);
530void MyApp::OnUnhandledException() {
537 }
catch (std::exception &e) {
539 what.Printf(
"standard exception with message \"%s\"", e.what());
541 what.Printf(
"standard exception of type \"%s\" with message \"%s\"",
542 typeid(e).name(), e.what());
545 what =
"unknown exception";
547 wxMessageOutputBest().Printf(
548 "Unhandled %s; terminating %s.\n", what,
549 wxIsMainThread() ?
"the application" :
"the thread in which it happened");
552bool MyApp::OpenFile(
const std::string &path) {
554 auto result = nav_objects.load_file(path.c_str());
556 std::string s(_(
"Cannot load route or waypoint file: "));
557 s += std::string(
"\"") + path +
"\"";
558 wxMessageBox(s,
"OpenCPN", wxICON_WARNING | wxOK);
564 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups,
true);
568 LLBBox box = nav_objects.GetBBox();
569 if (box.GetValid()) {
570 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
576void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
579 parser.AddSwitch(
"h",
"help",
"", wxCMD_LINE_OPTION_HELP);
580 parser.AddSwitch(
"p",
"portable");
581 parser.AddOption(
"c",
"configdir",
"", wxCMD_LINE_VAL_STRING,
582 wxCMD_LINE_PARAM_OPTIONAL);
583 parser.AddSwitch(
"f",
"fullscreen");
584 parser.AddSwitch(
"G",
"no_opengl");
585 parser.AddSwitch(
"W",
"config_wizard");
586 parser.AddSwitch(
"g",
"rebuild_gl_raster_cache");
587 parser.AddSwitch(
"D",
"rebuild_chart_db");
588 parser.AddSwitch(
"P",
"parse_all_enc");
589 parser.AddOption(
"l",
"loglevel");
590 parser.AddOption(
"u",
"unit_test_1",
"", wxCMD_LINE_VAL_NUMBER);
591 parser.AddSwitch(
"U",
"unit_test_2");
592 parser.AddParam(
"import GPX files", wxCMD_LINE_VAL_STRING,
593 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
594 parser.AddSwitch(
"s",
"safe_mode");
595 parser.AddSwitch(
"r",
"remote");
596 parser.AddSwitch(
"R",
"raise");
597 parser.AddSwitch(
"q",
"quit");
598 parser.AddSwitch(
"e",
"get_rest_endpoint");
599 parser.AddOption(
"o",
"open",
"", wxCMD_LINE_VAL_STRING,
600 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
606static void ParseLoglevel(wxCmdLineParser &parser) {
607 wxLog::SetLogLevel(wxLOG_Message);
610static void ParseLoglevel(wxCmdLineParser &parser) {
611 const char *strLevel = std::getenv(
"OPENCPN_LOGLEVEL");
612 strLevel = strLevel ? strLevel :
"info";
614 if (parser.Found(
"l", &wxLevel)) {
615 strLevel = wxLevel.c_str();
617 wxLogLevel level = OcpnLog::str2level(strLevel);
618 if (level == OcpnLog::LOG_BADLEVEL) {
619 fprintf(stderr,
"Bad loglevel %s, using \"info\"", strLevel);
622 wxLog::SetLogLevel(level);
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; }
731static wxStopWatch init_sw;
734 if (m_exitcode != -2)
return m_exitcode;
735 return wxAppConsole::OnRun();
746 if (!wxGetEnv(
"OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
747 if (wxGetEnv(
"WAYLAND_DISPLAY", NULL)) {
748 setenv(
"GDK_BACKEND",
"x11", 1);
752 "mesa_glthread",
"false",
761 if (!wxApp::OnInit())
return false;
764 androidEnableBackButton(
false);
765 androidEnableOptionItems(
false);
770#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
776 wxBitmap bmp(10, 10, -1);
778 dc.SelectObject(bmp);
779 dc.DrawText(
"X", 0, 0);
794 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
798 std::cerr <<
"No remote opencpn found. Giving up.\n";
803 std::unique_ptr<LocalClientApi> client;
805 client = LocalClientApi::GetClient();
807 WARNING_LOG <<
"Ipc client exception: " << ie.str();
814 wxMessageBox(_(
"Sorry, an existing instance of OpenCPN may be too busy "
815 "to respond.\nPlease retry."),
816 "OpenCPN", wxICON_INFORMATION | wxOK);
821 auto result = client->HandleCmdline(m_parsed_cmdline.action,
822 m_parsed_cmdline.arg);
826 wxLogDebug(
"Error running remote command: %s", result.second.c_str());
835 if (getenv(
"OPENCPN_FATAL_ERROR") != 0) {
836 wxLogFatalError(getenv(
"OPENCPN_FATAL_ERROR"));
847 OCPNPlatform::Initialize_1();
852 MyApp::SetAppDisplayName(
"OpenCPN");
855 wxDateTime x = wxDateTime::UNow();
856 long seed = x.GetMillisecond();
857 seed *= x.GetTicks();
862 setlocale(LC_NUMERIC,
"C");
864 g_start_time = wxDateTime::Now();
866 g_loglast_time = g_start_time;
867 g_loglast_time.MakeGMT();
868 g_loglast_time.Subtract(
869 wxTimeSpan(0, 29, 0, 0));
871 AnchorPointMinDist = 5.0;
877 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
881 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
882 wxFONTWEIGHT_NORMAL, FALSE, wxString(
""),
883 wxFONTENCODING_SYSTEM);
884 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
887 auto ¬eman = NotificationManager::GetInstance();
888 noteman.ScrubNotificationDirectory(30);
891 if (!g_Platform->InitializeLogFile()) {
903 wxLogMessage(
"\n\n________\n");
905 wxDateTime now = wxDateTime::Now();
906 LOG_INFO(
"------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
907 now.FormatISODate().mb_str().data());
908 wxLogLevel level = wxLog::GetLogLevel();
909 LOG_INFO(
"Using loglevel %s", OcpnLog::level2str(level).c_str());
911 wxString wxver(wxVERSION_STRING);
912 wxver.Prepend(
"wxWidgets version: ");
914 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
918 os_name = platforminfo.GetOperatingSystemIdName();
920 os_name = platforminfo.GetOperatingSystemFamilyName();
923 wxString platform = os_name +
" " + platforminfo.GetArchName() +
" " +
924 platforminfo.GetPortIdName();
926 wxLogMessage(wxver +
" " + platform);
928 ::wxGetOsVersion(&osMajor, &osMinor);
929 wxString osVersionMsg;
930 osVersionMsg.Printf(
"OS Version reports as: %d.%d", osMajor, osMinor);
931 wxLogMessage(osVersionMsg);
933 wxLogMessage(
"MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
934 g_mem_total / 1024, g_mem_initial / 1024);
939 if (!detail->osd_names_like.empty())
940 like0 = detail->osd_names_like[0].c_str();
941 msgplat.Printf(
"OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
942 detail->osd_arch.c_str(), detail->osd_name.c_str(),
943 detail->osd_version.c_str(), detail->osd_ID.c_str(),
945 wxLogMessage(msgplat);
947 wxString imsg =
"SData_Locn is ";
948 imsg += g_Platform->GetSharedDataDir();
952 ::wxInitAllImageHandlers();
956 prepareAndroidStyleSheets();
960 pInit_Chart_Dir =
new wxString();
965 imsg =
"PrivateDataDir is ";
971 navutil::InitGlobals();
975 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
979 pSelect->SetSelectPixelRadius(12);
992 g_pais_query_dialog_active = NULL;
995 g_hostname = ::wxGetHostName();
996 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
998 androidGetDeviceInfo();
999 g_hostname = wxString(
"Android-") + g_android_Device_Model;
1000 g_hostname.Replace(
" ",
"-",
true);
1005 wxString p(
"Portable-");
1006 g_hostname = p + g_hostname;
1011 pLayerList =
new LayerList;
1016 auto &navobj_db = NavObj_dB::GetInstance();
1023#ifdef PROBE_PORTS__WITH_HELPER
1024 user_user_id = getuid();
1025 file_user_id = geteuid();
1029 bool b_initial_load =
false;
1031 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
1032 if (config_test_file_name.FileExists())
1033 wxLogMessage(
"Using existing Config_File: " +
1034 g_Platform->GetConfigFileName());
1037 wxLogMessage(
"Creating new Config_File: " +
1038 g_Platform->GetConfigFileName());
1040 b_initial_load =
true;
1043 config_test_file_name.DirExists(config_test_file_name.GetPath()))
1044 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
1045 wxLogMessage(
"Cannot create config file directory for " +
1046 g_Platform->GetConfigFileName());
1051 pConfig = g_Platform->GetConfigObject();
1055 if (g_kiosk_startup) {
1057 g_wallpaper->ShowFullScreen(
true);
1058 g_wallpaper->Show();
1063 if (b_initial_load) g_Platform->SetDefaultOptions();
1065 g_Platform->applyExpertMode(g_bUIexpert);
1070 g_StyleManager->SetStyle(
"MUI_flat");
1071 if (!g_StyleManager->IsOK()) {
1072 wxString msg = _(
"Failed to initialize the user interface. ");
1073 msg << _(
"OpenCPN cannot start. ");
1074 msg << _(
"The necessary configuration files were not found. ");
1075 msg << _(
"See the log file at ") << g_Platform->GetLogFileName()
1076 << _(
" for details.") <<
"\n\n";
1077 msg << g_Platform->GetSharedDataDir();
1079 wxMessageDialog w(NULL, msg, _(
"Failed to initialize the user interface. "),
1080 wxCANCEL | wxICON_ERROR);
1087 if (style) style->chartStatusWindowTransparent =
true;
1091 pWayPointMan = NULL;
1095 msg.Printf(
"Detected display size (horizontal): %d mm",
1100 if (g_config_display_size_manual &&
1105 msg.Printf(
"Display size (horizontal) config override: %d mm",
1114 int SelectPixelRadius = 50;
1116 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1117 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1118 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1122 if (!n_NavMessageShown) {
1129#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1132 g_Platform->SetLocaleSearchPrefixes();
1134 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1136 imsg =
"System default Language: " + def_lang_canonical;
1139 wxString cflmsg =
"Config file language: " + g_locale;
1140 wxLogMessage(cflmsg);
1142 if (g_locale.IsEmpty()) {
1143 g_locale = def_lang_canonical;
1144 cflmsg =
"Config file language empty, using system default: " + g_locale;
1145 wxLogMessage(cflmsg);
1149 g_locale = g_Platform->GetAdjustedAppLocale();
1150 cflmsg =
"Adjusted App language: " + g_locale;
1151 wxLogMessage(cflmsg);
1154 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1156 imsg =
"Opencpn language set to: ";
1163 if (g_locale ==
"fr_FR") g_b_assume_azerty =
true;
1165 wxLogMessage(
"wxLocale support not available");
1170 if (g_config_wizard || b_initial_load) {
1172 auto res = wiz.Run();
1183 wxString vs = wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1184 g_bUpgradeInProcess = (vs != g_config_version_string);
1186 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1189 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1190 wxLogMessage(g_Platform->GetLargeLogMessage());
1195 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();
1249 new_msg_type_listener.Init(NavMsgBus::GetInstance().new_msg_event,
1253 gDefaultWorldMapLocation =
"gshhs";
1254 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1255 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1256 if (gWorldMapLocation == wxEmptyString) {
1257 gWorldMapLocation = gDefaultWorldMapLocation;
1262 wxString default_tcdata0 =
1263 (g_Platform->GetSharedDataDir() +
"tcdata" +
1264 wxFileName::GetPathSeparator() +
"harmonics-dwf-20210110-free.tcd");
1265 wxString default_tcdata1 =
1266 (g_Platform->GetSharedDataDir() +
"tcdata" +
1267 wxFileName::GetPathSeparator() +
"HARMONICS_NO_US.IDX");
1268 wxString default_tcdata2 =
1269 (g_Platform->GetSharedDataDir() +
"tcdata" +
1270 wxFileName::GetPathSeparator() +
"ticon-europe-global.tcd");
1272 if (TideCurrentDataSet.empty()) {
1273 TideCurrentDataSet.push_back(
1274 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1275 TideCurrentDataSet.push_back(
1276 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1277 TideCurrentDataSet.push_back(
1278 g_Platform->NormalizePath(default_tcdata2).ToStdString());
1283 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1284 wxString default_sound = (g_Platform->GetSharedDataDir() +
"sounds" +
1285 wxFileName::GetPathSeparator() +
"2bells.wav");
1286 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1291 g_Platform->Initialize_2();
1293 LoadChartDatabase();
1297 g_kiosk_startup =
false;
1301 if (!g_kiosk_startup) {
1303 SetTopWindow(gFrame);
1310 OCPNPlatform::Initialize_4();
1313 androidHideBusyIcon();
1316 wxString::Format(_(
"OpenCPN Initialized in %ld ms."), init_sw.Time()));
1320 if (!g_kiosk_startup) {
1321 if (!DoNavMessage(vs)) {
1328 g_bHasHwClock =
true;
1329#if defined(__UNIX__) && !defined(__ANDROID__)
1332 ((stat(
"/dev/rtc", &buffer) == 0) || (stat(
"/dev/rtc0", &buffer) == 0) ||
1333 (stat(
"/dev/misc/rtc", &buffer) == 0));
1336 g_config_version_string = vs;
1341 for (
auto *cp : TheConnectionParams()) {
1343 if (cp->GetDSPort().Contains(
"Serial")) {
1344 std::string port(cp->Port.ToStdString());
1351 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1354 if (ipv4_addrs.size()) {
1355 std::string ipAddr = ipv4_addrs[0];
1358 if (data_dir.Last() != wxFileName::GetPathSeparator())
1359 data_dir.Append(wxFileName::GetPathSeparator());
1361 make_certificate(ipAddr, data_dir.ToStdString());
1363 m_rest_server.
StartServer(fs::path(data_dir.ToStdString()));
1364 StartMDNSService(g_hostname.ToStdString(),
"opencpn-object-control-service",
1368 if (!g_kiosk_startup) {
1372 wxLogMessage(
"InitTimer start");
1373 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1383 CallAfter([
this]() {
1385 g_wallpaper->Show(
false);
1387 g_bFullscreen =
true;
1390 g_wallpaper->Destroy();
1391 g_wallpaper =
nullptr;
1393 SetTopWindow(gFrame);
1397 wxString(
"Version ") + VERSION_FULL +
" Build " + VERSION_DATE;
1398 if (!DoNavMessage(vs)) {
1404 wxLogMessage(
"InitTimer start");
1405 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1410void MyApp::BuildMainFrame() {
1413 wxSize new_frame_size(-1, -1);
1415 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1417 user_colors::Initialize();
1419 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1420 (g_nframewin_y <= ch))
1421 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1423 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1429 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1430 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1431 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1432 g_bframemax =
false;
1435 g_lastClientRectx = cx;
1436 g_lastClientRecty = cy;
1437 g_lastClientRectw = cw;
1438 g_lastClientRecth = ch;
1441 wxPoint position(0, 0);
1442 wxSize dsize = wxGetDisplaySize();
1445 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1448 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1449 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1454 frame_rect.left = position.x;
1455 frame_rect.top = position.y;
1456 frame_rect.right = position.x + new_frame_size.x;
1457 frame_rect.bottom = position.y + new_frame_size.y;
1461 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1462 position = wxPoint(10, 10);
1467 const wxPoint ptScreen(position.x, position.y);
1468 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1470 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1473 g_nframewin_posx = position.x;
1474 g_nframewin_posy = position.y;
1477 wxSize asz = getAndroidDisplayDimensions();
1482 if ((cw > 200) && (ch > 200))
1483 new_frame_size.Set(cw, ch);
1485 new_frame_size.Set(800, 400);
1491 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst(
'+');
1492 wxString myframe_window_title = wxString(
"OpenCPN " + short_version_name);
1495 myframe_window_title += _(
" -- [Portable(-p) executing from ");
1496 myframe_window_title += g_Platform->GetHomeDir();
1497 myframe_window_title +=
"]";
1501 fmsg.Printf(
"Creating MyFrame...size(%d, %d) position(%d, %d)",
1502 new_frame_size.x, new_frame_size.y, position.x, position.y);
1506 auto dockart =
new wxAuiDefaultDockArt;
1509 gFrame =
new MyFrame(myframe_window_title, position, new_frame_size,
1510 m_rest_server, dockart,
1511 [&](
const std::string &path) {
return OpenFile(path); });
1516 g_pauimgr->SetDockSizeConstraint(.9, .9);
1522 g_Platform->Initialize_3();
1524 gFrame->CreateCanvasLayout();
1526 gFrame->SetGPSCompassScale();
1530 gFrame->SetChartUpdatePeriod();
1534 gFrame->ApplyGlobalSettings(
false);
1535 gFrame->SetAllToolbarScale();
1536 gFrame->SetAndApplyColorScheme(global_color_scheme);
1537 if (g_bframemax) gFrame->Maximize(
true);
1540 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->
GetPixPerMM() > 4.0))
1541 gFrame->Maximize(
true);
1550 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1551 g_GLOptions.m_bTextureCompressionCaching) {
1552 gFrame->ReloadAllVP();
1571 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1575 dogmsg.Printf(
"GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1576 wxLogMessage(dogmsg);
1578 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1586 if (g_bTrackCarryOver) g_bDeferredStartTrack =
true;
1591 gFrame->DoChartUpdate();
1593 CommBridge::GetInstance();
1596 for (
auto *cp : TheConnectionParams()) {
1599 cp->b_IsSetup = TRUE;
1606 auto style = g_StyleManager->GetCurrentStyle();
1607 auto bitmap =
new wxBitmap(style->GetIcon(
"default_pi", 32, 32));
1609 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1611 wxLogWarning(
"Cannot initiate plugin default jigsaw icon.");
1613 AbstractPlatform::ShowBusySpinner();
1615 AbstractPlatform::HideBusySpinner();
1619 wxString perspective;
1621 pConfig->Read(
"AUIPerspective", &perspective);
1628 bool bno_load =
false;
1630 wxArrayString name_array;
1631 wxStringTokenizer st(perspective,
"|;");
1632 while (st.HasMoreTokens()) {
1633 wxString s1 = st.GetNextToken();
1634 if (s1.StartsWith(
"name=")) {
1635 wxString sc = s1.AfterFirst(
'=');
1640 wxAuiPaneInfoArray pane_array_val =
g_pauimgr->GetAllPanes();
1641 for (
unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1642 wxAuiPaneInfo pane = pane_array_val.Item(i);
1646 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1652 if (!bno_load)
g_pauimgr->LoadPerspective(perspective,
false);
1657 for (
unsigned int i = 0; i <
g_canvasArray.GetCount(); i++) {
1660 wxSize frameSize = GetClientSize();
1661 wxSize minSize =
g_pauimgr->GetPane(cc).min_size;
1662 int width = wxMax(minSize.x, frameSize.x / 10);
1663 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1685 if (!g_bdisable_opengl) {
1688 if (pgl && (pgl->GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)) {
1689 gFrame->m_defer_size = gFrame->GetSize();
1690 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1692 gFrame->m_bdefer_resize =
true;
1702 glDeleteTextures(n, texts);
1711 gFrame->SetSize(getAndroidDisplayDimensions());
1712 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1724void MyApp::LoadChartDatabase() {
1726 ArrayOfCDI ChartDirArray;
1727 pConfig->LoadChartDirArray(ChartDirArray);
1732 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1735 wxRegKey RegKey(wxString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1736 if (RegKey.Exists()) {
1738 _(
"Retrieving initial Chart Directory set from Windows Registry"));
1740 RegKey.QueryValue(wxString(
"ChartDirs"), dirs);
1742 wxStringTokenizer tkz(dirs,
";");
1743 while (tkz.HasMoreTokens()) {
1744 wxString token = tkz.GetNextToken();
1747 cdi.fullpath = token.Trim();
1748 cdi.magic_number =
"";
1750 ChartDirArray.Add(cdi);
1757 cdi.fullpath =
"charts";
1758 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1759 cdi.magic_number =
"";
1760 ChartDirArray.Add(cdi);
1764 if (ndirs)
pConfig->UpdateChartDirs(ChartDirArray);
1774 if (!ChartDirArray.GetCount())
1775 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1782 g_restore_dbindex = 0;
1786 if (g_restore_dbindex >= 0) {
1787 if (
ChartData->GetChartTableEntries() == 0)
1788 g_restore_dbindex = -1;
1790 else if (g_restore_dbindex > (
ChartData->GetChartTableEntries() - 1))
1791 g_restore_dbindex = 0;
1799 wxLogMessage(
"opencpn::MyApp starting exit.");
1801 m_usb_watcher.Stop();
1804 wxDateTime lognow = wxDateTime::Now();
1806 wxString day = lognow.FormatISODate();
1807 wxString utc = lognow.FormatISOTime();
1808 wxString navmsg =
"LOGBOOK: ";
1816 data.Printf(
"OFF: Lat %10.5f Lon %10.5f ",
gLat,
gLon);
1820 if (std::isnan(
gCog))
1821 cog.Printf(
"COG ----- ");
1823 cog.Printf(
"COG %10.5f ",
gCog);
1826 if (std::isnan(
gSog))
1827 sog.Printf(
"SOG ----- ");
1829 sog.Printf(
"SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(
gSog));
1836 data.Printf(
"OFF: Lat %10.5f Lon %10.5f",
gLat,
gLon);
1839 wxLogMessage(navmsg);
1840 g_loglast_time = lognow;
1858 for (
unsigned int igroup = 0; igroup <
g_pGroupArray->GetCount();
1867 wxLogMessage(
"opencpn::MyApp exiting cleanly...\n");
1868 wxLog::FlushActive();
1870 g_Platform->CloseLogFile();
1872 delete pInit_Chart_Dir;
1880 delete pWayPointMan;
1882 navutil::DeinitGlobals();
1884 user_colors::DeInitialize();
1891 delete g_StyleManager;
1896 void RestoreSystemColors();
1897 RestoreSystemColors();
1904#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1908 FontMgr::Shutdown();
1910 g_Platform->OnExit_2();
1917#ifdef LINUX_CRASHRPT
1918void MyApp::OnFatalException() { g_crashprint.Report(); }
1924void MyCPLErrorHandler(CPLErr eErrClass,
int nError,
const char *pszErrorMsg)
1929 if (eErrClass == CE_Debug)
1930 snprintf(msg, 255,
"CPL: %s", pszErrorMsg);
1931 else if (eErrClass == CE_Warning)
1932 snprintf(msg, 255,
"CPL Warning %d: %s", nError, pszErrorMsg);
1934 snprintf(msg, 255,
"CPL ERROR %d: %s", nError, pszErrorMsg);
1936 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.
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.
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.
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)
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()
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 MarkStartAsOk()
Mark last run as successful.
bool GetMode()
Return true if we are running in safe mode.
void CheckLastStart()
Check if the last start failed, possibly invoke user dialog and set safe mode state.
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.
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.