OpenCPN Partial API docs
Loading...
Searching...
No Matches
ocpn_app.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 **************************************************************************/
19
26#include "config.h"
27
28#include <algorithm>
29#include <limits.h>
30#include <memory>
31#include <thread>
32
33#ifdef __WXMSW__
34#include <math.h>
35#include <psapi.h>
36#include <stdlib.h>
37#include <time.h>
38#endif
39
40#ifndef __WXMSW__
41#include <setjmp.h>
42#include <signal.h>
43#endif
44
45#ifdef OCPN_HAVE_X11
46#include <X11/Xatom.h>
47#include <X11/Xlib.h>
48#endif
49
50#ifdef __VISUALC__
51#include <wx/msw/msvcrt.h>
52#endif
53
54#ifdef __MINGW32__
55#undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
56#include <windows.h>
57#endif
58
59#ifdef __WXMSW__
60// #include "c:\\Program Files\\visual leak detector\\include\\vld.h"
61#endif
62
63#if defined(__WXMSW__) && defined(__MSVC__LEAK)
64#include "Stackwalker.h"
65#endif
66
67#include <wx/wxprec.h>
68
69#ifndef WX_PRECOMP
70#include <wx/wx.h>
71#endif // precompiled headers
72
73#include <wx/apptrait.h>
74#include <wx/arrimpl.cpp>
75#include <wx/artprov.h>
76#include <wx/aui/aui.h>
77#include <wx/aui/dockart.h>
78#include <wx/clrpicker.h>
79#include <wx/cmdline.h>
80#include <wx/dialog.h>
81#include <wx/dialog.h>
82#include <wx/dir.h>
83#include <wx/display.h>
84#include <wx/dynlib.h>
85#include <wx/image.h>
86#include <wx/intl.h>
87#include <wx/ipc.h>
88#include <wx/jsonreader.h>
89#include <wx/listctrl.h>
90#include <wx/power.h>
91#include <wx/printdlg.h>
92#include <wx/print.h>
93#include <wx/progdlg.h>
94#include <wx/settings.h>
95#include <wx/stdpaths.h>
96#include <wx/tokenzr.h>
97
98#include "o_sound/o_sound.h"
99
100#include "model/ais_decoder.h"
101#include "model/ais_state_vars.h"
102#include "model/certificates.h"
103#include "model/cmdline.h"
104#include "model/comm_bridge.h"
106#include "model/comm_vars.h"
107#include "model/config_vars.h"
108#include "model/gui_vars.h"
109#include "model/instance_check.h"
110#include "model/local_api.h"
111#include "model/logger.h"
112#include "model/mdns_query.h"
113#include "model/mdns_service.h"
114#include "model/multiplexer.h"
115#include "model/navobj_db.h"
116#include "model/nav_object_database.h"
117#include "model/navutil_base.h"
119#include "model/own_ship.h"
120#include "model/plugin_handler.h"
121#include "model/route.h"
122#include "model/routeman.h"
123#include "model/select.h"
124#include "model/track.h"
125
126#include "about_frame_impl.h"
127#include "about.h"
128#include "ais_info_gui.h"
129#include "ais_target_alert_dlg.h"
130#include "ais_target_list_dlg.h"
131#include "ais_target_query_dlg.h"
132#include "canvas_config.h"
133#include "chartdb.h"
134#include "chcanv.h"
135#include "cm93.h"
136#include "concanv.h"
137#include "config.h"
138#include "config_mgr.h"
139#include "detail_slider.h"
140#include "dychart.h"
141#include "font_mgr.h"
142#include "gdal/cpl_csv.h"
143#include "gl_tex_cache.h"
144#include "go_to_position_dlg.h"
145#include "layer.h"
146#include "mark_info.h"
147#include "navutil.h"
148#include "observable.h"
149#include "ocpn_app.h"
150#include "ocpn_aui_manager.h"
151#include "ocpn_frame.h"
152#include "ocpn_platform.h"
153#include "o_senc.h"
154#include "options.h"
155#include "rest_server_gui.h"
156#include "route_ctx_factory.h"
157#include "routemanagerdialog.h"
158#include "routeman_gui.h"
159#include "route_prop_dlg_impl.h"
160#include "s52plib.h"
161#include "s57chart.h"
162#include "s57_query_dlg.h"
163#include "safe_mode_gui.h"
164#include "std_filesystem.h"
165#include "styles.h"
166#include "tcmgr.h"
167#include "thumbwin.h"
168#include "track_prop_dlg.h"
169#include "udev_rule_mgr.h"
170#include "wiz_ui.h"
171
172#ifdef ocpnUSE_GL
173#include "gl_chart_canvas.h"
174#endif
175
176#ifdef __WXOSX__
177#include "model/macutils.h"
178#endif
179
180#ifdef __WXMSW__
181#include "model/garmin_protocol_mgr.h" // Used for port probing on Windows
182void RedirectIOToConsole();
183#endif
184
185#ifdef LINUX_CRASHRPT
186#include "crashprint.h"
187#endif
188
189#ifdef __WXOSX__
190#include "model/macutils.h"
191#endif
192
193#ifdef __ANDROID__
194#include "androidUTIL.h"
195#else
196#include "serial/serial.h"
197#endif
198
199using namespace std::literals::chrono_literals;
200
201const char *const kUsage =
202 R"(Usage:
203 opencpn -h | --help
204 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
205 opencpn --remote [-R] | -q] | -e] |-o <str>]
206
207Options for starting opencpn
208
209 -c, --configdir=<dirpath> Use alternative configuration directory.
210 -p, --portable Run in portable mode.
211 -f, --fullscreen Switch to full screen mode on start.
212 -G, --no_opengl Disable OpenGL video acceleration. This setting will
213 be remembered.
214 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
215 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
216 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
217 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
218 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
219 Zero or negative <num> specifies no limit.
220 -U, --unit_test_2
221 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
222 -W, --config_wizard Start with initial configuration wizard
223
224Options manipulating already started opencpn
225 -r, --remote Execute commands on already running instance
226 -R, --raise Make running OpenCPN visible if hidden
227 -q, --quit Terminate already running opencpn
228 -e, --get_rest_endpoint Print rest server endpoint and exit.
229 -o, --open=<GPX file> Open file in running opencpn
230
231Arguments:
232 GPX file GPX-formatted file with waypoints or routes.
233)";
234
235// comm event definitions
236wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
237wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
238
239wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
240wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
241wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
242wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
243wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
244wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
245wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
246wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
247wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
248
249//------------------------------------------------------------------------------
250// Fwd Declarations
251//------------------------------------------------------------------------------
252
253//------------------------------------------------------------------------------
254// Static variable definition
255//------------------------------------------------------------------------------
256
257WX_DEFINE_OBJARRAY(ArrayOfCDI);
258
259static int user_user_id;
260static int file_user_id;
261
262static int g_mem_total, g_mem_initial;
263
264static unsigned int malloc_max;
265
266static int osMajor, osMinor;
267
268static bool g_bHasHwClock;
269
270#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
271// FIXME (leamas) find a new home
272wxLocale *plocale_def_lang = 0;
273#endif
274
275#ifdef LINUX_CRASHRPT
276static wxCrashPrint g_crashprint;
277#endif
278
279#ifndef __WXMSW__
280extern sigjmp_buf env; // the context saved by sigsetjmp();
281#endif // FIXME (leamas) Use exceptions
282
283// {2C9C45C2-8E7D-4C08-A12D-816BBAE722C0}
284#ifdef __WXMSW__
285DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
286 0x6b, 0xba, 0xe7, 0x22, 0xc0);
287#endif
288
289#if !defined(NAN)
290static const long long lNaN = 0xfff8000000000000;
291#define NAN (*(double *)&lNaN)
292#endif
293
294// Some static helpers
295void appendOSDirSlash(wxString *pString);
296
297void InitializeUserColors();
298void DeInitializeUserColors();
299void SetSystemColors(ColorScheme cs);
300
301static bool LoadAllPlugIns(bool load_enabled) {
302 g_Platform->ShowBusySpinner();
303 bool b = PluginLoader::GetInstance()->LoadAllPlugIns(load_enabled);
304 g_Platform->HideBusySpinner();
305 return b;
306}
307
308//------------------------------------------------------------------------------
309// PNG Icon resources
310//------------------------------------------------------------------------------
311
312#if defined(__WXGTK__) || defined(__WXQT__)
313#include "bitmaps/opencpn.xpm"
314#endif
315
316wxString newPrivateFileName(wxString, const char *name,
317 [[maybe_unused]] const char *windowsName) {
318 wxString fname = wxString::FromUTF8(name);
319 wxString filePathAndName;
320
321 filePathAndName = g_Platform->GetPrivateDataDir();
322 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
323 filePathAndName.Append(wxFileName::GetPathSeparator());
324
325#ifdef __WXMSW__
326 wxString fwname = wxString::FromUTF8(windowsName);
327 filePathAndName.Append(fwname);
328#else
329 filePathAndName.Append(fname);
330#endif
331
332 return filePathAndName;
333}
334
335class WallpaperFrame : public wxFrame {
336public:
338 : wxFrame(nullptr, wxID_ANY, "Loading...", wxDefaultPosition,
339 wxSize(900, 600), wxSTAY_ON_TOP) {
340 // Customize the wallpaper appearance
341 SetBackgroundColour(wxColour(0, 0, 0)); // Black background
342
343 // Add a text message
344 wxStaticText *text =
345 new wxStaticText(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize,
346 wxALIGN_CENTRE_HORIZONTAL);
347 text->SetForegroundColour(wxColour(255, 255, 255));
348
349 wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
350 sizer->Add(text, 1, wxALIGN_CENTER);
351 SetSizerAndFit(sizer);
352
353 Center(); // Center the wallpaper frame
354 }
355};
356
357// `Main program` equivalent, creating windows and returning main app frame
358//------------------------------------------------------------------------------
359// MyApp
360//------------------------------------------------------------------------------
361IMPLEMENT_APP(MyApp)
362
363BEGIN_EVENT_TABLE(MyApp, wxApp)
364EVT_ACTIVATE_APP(MyApp::OnActivateApp)
365END_EVENT_TABLE()
366
367static void ActivateRoute(const std::string &guid) {
368 Route *route = g_pRouteMan->FindRouteByGUID(guid);
369 if (!route) {
370 wxLogMessage("Cannot activate guid: no such route");
371 return;
372 }
373 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
374 // If this is an auto-created MOB route, always select the second point
375 // (the MOB)
376 // as the destination.
377 RoutePoint *point;
378 if (wxNOT_FOUND == route->m_RouteNameString.Find("MOB")) {
379 point = g_pRouteMan->FindBestActivatePoint(route, gLat, gLon, gCog, gSog);
380 } else {
381 point = route->GetPoint(2);
382 }
383 g_pRouteMan->ActivateRoute(route, point);
385 route->m_bRtIsSelected = false;
386}
387
388static void ReverseRoute(const std::string &guid) {
389 Route *route = g_pRouteMan->FindRouteByGUID(guid);
390 if (!route) {
391 wxLogMessage("Cannot activate guid: no such route");
392 return;
393 }
394 route->Reverse();
396}
397
398void MyApp::InitRestListeners() {
399 auto activate_route = [&](wxCommandEvent ev) {
400 auto guid = ev.GetString().ToStdString();
401 ActivateRoute(guid);
402 };
403 rest_activate_listener.Init(m_rest_server.activate_route, activate_route);
404 auto reverse_route = [&](wxCommandEvent ev) {
405 auto guid = ev.GetString().ToStdString();
406 ReverseRoute(guid);
407 };
408 rest_reverse_listener.Init(m_rest_server.reverse_route, reverse_route);
409}
410
411bool MyApp::OpenFile(const std::string &path) {
412 NavObjectCollection1 nav_objects;
413 auto result = nav_objects.load_file(path.c_str());
414 if (!result) {
415 std::string s(_("Cannot load route or waypoint file: "));
416 s += std::string("\"") + path + "\"";
417 wxMessageBox(s, "OpenCPN", wxICON_WARNING | wxOK);
418 return false;
419 }
420
421 int wpt_dups;
422 // Import with full vizibility of names and objects
423 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups, true);
424
425 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
426 pRouteManagerDialog->UpdateLists();
427 LLBBox box = nav_objects.GetBBox();
428 if (box.GetValid()) {
429 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
430 }
431 return true;
432}
433
434#ifndef __ANDROID__
435void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
436 // Add OpenCPN specific command line options. Help message
437 // is hardcoded in kUsage;
438 parser.AddSwitch("h", "help", "", wxCMD_LINE_OPTION_HELP);
439 parser.AddSwitch("p", "portable");
440 parser.AddOption("c", "configdir", "", wxCMD_LINE_VAL_STRING,
441 wxCMD_LINE_PARAM_OPTIONAL);
442 parser.AddSwitch("f", "fullscreen");
443 parser.AddSwitch("G", "no_opengl");
444 parser.AddSwitch("W", "config_wizard");
445 parser.AddSwitch("g", "rebuild_gl_raster_cache");
446 parser.AddSwitch("D", "rebuild_chart_db");
447 parser.AddSwitch("P", "parse_all_enc");
448 parser.AddOption("l", "loglevel");
449 parser.AddOption("u", "unit_test_1", "", wxCMD_LINE_VAL_NUMBER);
450 parser.AddSwitch("U", "unit_test_2");
451 parser.AddParam("import GPX files", wxCMD_LINE_VAL_STRING,
452 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
453 parser.AddSwitch("s", "safe_mode");
454 parser.AddSwitch("r", "remote");
455 parser.AddSwitch("R", "raise");
456 parser.AddSwitch("q", "quit");
457 parser.AddSwitch("e", "get_rest_endpoint");
458 parser.AddOption("o", "open", "", wxCMD_LINE_VAL_STRING,
459 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
460}
461#endif // __ANDROID__
462
464#ifdef __ANDROID__
465static void ParseLoglevel(wxCmdLineParser &parser) {
466 wxLog::SetLogLevel(wxLOG_Message);
467}
468#else
469static void ParseLoglevel(wxCmdLineParser &parser) {
470 const char *strLevel = std::getenv("OPENCPN_LOGLEVEL");
471 strLevel = strLevel ? strLevel : "info";
472 wxString wxLevel;
473 if (parser.Found("l", &wxLevel)) {
474 strLevel = wxLevel.c_str();
475 }
476 wxLogLevel level = OcpnLog::str2level(strLevel);
477 if (level == OcpnLog::LOG_BADLEVEL) {
478 fprintf(stderr, "Bad loglevel %s, using \"info\"", strLevel);
479 level = wxLOG_Info;
480 }
481 wxLog::SetLogLevel(level);
482}
483#endif // __ANDROID__
484
485#ifndef __ANDROID__
486bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
487 std::cout << kUsage;
488 return false;
489}
490#endif
491
492#ifndef __ANDROID__
493bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
494 long number;
495 wxString repo;
496 wxString plugin;
497
498 g_unit_test_2 = parser.Found("unit_test_2");
499 g_bportable = parser.Found("p");
500 g_start_fullscreen = parser.Found("fullscreen");
501 g_bdisable_opengl = parser.Found("no_opengl");
502 g_rebuild_gl_cache = parser.Found("rebuild_gl_raster_cache");
503 g_NeedDBUpdate = parser.Found("rebuild_chart_db") ? 2 : 0;
504 g_parse_all_enc = parser.Found("parse_all_enc");
505 g_config_wizard = parser.Found("config_wizard");
506 if (parser.Found("unit_test_1", &number)) {
507 g_unit_test_1 = static_cast<int>(number);
508 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
509 }
510 safe_mode::set_mode(parser.Found("safe_mode"));
511 ParseLoglevel(parser);
512 wxString wxstr;
513 if (parser.Found("configdir", &wxstr)) {
514 g_configdir = wxstr.ToStdString();
515 fs::path path(g_configdir);
516 if (!fs::exists(path) || !fs::is_directory(path)) {
517 std::cerr << g_configdir << " is not an existing directory.\n";
518 return false;
519 }
520 }
521
522 bool has_start_options = false;
523 static const std::vector<std::string> kStartOptions = {
524 "unit_test_2",
525 "p",
526 "fullscreen",
527 "no_opengl",
528 "rebuild_gl_raster_cache",
529 "rebuild_chart_db",
530 "parse_all_enc",
531 "unit_test_1",
532 "safe_mode",
533 "loglevel"};
534 for (const auto &opt : kStartOptions) {
535 if (parser.Found(opt)) has_start_options = true;
536 }
537 if (has_start_options && parser.Found("remote")) {
538 std::cerr << "this option is not compatible with --remote\n";
539 return false;
540 }
541
542 bool has_remote_options = false;
543 static const std::vector<std::string> kRemoteOptions = {
544 "raise", "quit", "open", "get_rest_endpoint"};
545 for (const auto &opt : kRemoteOptions) {
546 if (parser.Found(opt)) has_remote_options = true;
547 }
548 if (has_remote_options && !parser.Found("remote")) {
549 std::cerr << "This option requires --remote\n";
550 return false;
551 }
552
553 for (size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
554 g_params.push_back(parser.GetParam(paramNr).ToStdString());
555
556 wxString optarg;
557 if (!parser.Found("remote"))
558 m_parsed_cmdline = ParsedCmdline();
559 else if (parser.Found("raise"))
560 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
561 else if (parser.Found("quit"))
562 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
563 else if (parser.Found("get_rest_endpoint"))
564 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
565 else if (parser.Found("open", &optarg))
566 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
567 else if (parser.GetParamCount() == 1)
568 m_parsed_cmdline =
569 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
570 else if (!has_start_options && !has_remote_options) {
571 // Neither arguments nor options
572 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
573 }
574 return true;
575}
576#endif // __ANDROID__
577
578#ifdef __WXMSW__
579// Handle any exception not handled by CrashRpt
580// Most probable: Malloc/new failure
581
582bool MyApp::OnExceptionInMainLoop() {
583 wxLogWarning("Caught MainLoopException, continuing...");
584 return true;
585}
586#endif
587
588void MyApp::OnActivateApp(wxActivateEvent &event) { return; }
589
590static wxStopWatch init_sw;
591
592int MyApp::OnRun() {
593 if (m_exitcode != -2) return m_exitcode;
594 return wxAppConsole::OnRun();
595}
596
597MyApp::MyApp()
598 : m_checker(InstanceCheck::GetInstance()),
599 m_rest_server(PINCreateDialog::GetDlgCtx(), RouteCtxFactory(),
600 g_bportable),
601 m_usb_watcher(UsbWatchDaemon::GetInstance()),
602 m_exitcode(-2) {
603#ifdef __linux__
604 // Handle e. g., wayland default display -- see #1166.
605 if (!wxGetEnv("OCPN_DISABLE_X11_GDK_BACKEND", NULL)) {
606 if (wxGetEnv("WAYLAND_DISPLAY", NULL)) {
607 setenv("GDK_BACKEND", "x11", 1);
608 }
609 }
610 setenv(
611 "mesa_glthread", "false",
612 1); // Explicitly disable glthread. This may have some impact on OpenGL
613 // performance, but we know it is problematic for us. See #2889
614#endif // __linux__
615}
616
617WallpaperFrame *g_wallpaper;
618
620 if (!wxApp::OnInit()) return false;
621
622#ifdef __ANDROID__
623 androidEnableBackButton(false);
624 androidEnableOptionItems(false);
625#endif
626
628
629#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
630 // There is a race condition between cairo which is used for text rendering
631 // by gtk and EGL which without the below code causes a bus error and the
632 // program aborts before startup
633 // this hack forces cairo to load right now by rendering some text
634
635 wxBitmap bmp(10, 10, -1);
636 wxMemoryDC dc;
637 dc.SelectObject(bmp);
638 dc.DrawText("X", 0, 0);
639#endif
640
641 // Instantiate the global OCPNPlatform class
642 g_Platform = new OCPNPlatform;
643 g_BasePlatform = g_Platform;
644#ifndef __ANDROID__
645 // We allow only one instance unless the portable option is used
646 if (!g_bportable && wxDirExists(g_Platform->GetPrivateDataDir())) {
647 m_checker.WaitUntilValid();
648 if (m_checker.IsMainInstance()) {
649 // Server is created on first call to GetInstance()
650 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
651 // Server starts running when referenced.
652 [[maybe_unused]] auto &server = LocalServerApi::GetInstance();
653 } else {
654 std::cerr << "No remote opencpn found. Giving up.\n";
655 m_exitcode = 1;
656 return true;
657 }
658 } else {
659 std::unique_ptr<LocalClientApi> client;
660 try {
661 client = LocalClientApi::GetClient();
662 } catch (LocalApiException &ie) {
663 WARNING_LOG << "Ipc client exception: " << ie.str();
664 // If we get here it means that the instance_chk found another
665 // running instance. But that instance is for some reason not
666 // reachable. The safe thing to do is delete the lockfile and exit.
667 // Next start will proceed normally. This may leave a zombie OpenCPN,
668 // but at least O starts.
669 m_checker.CleanUp();
670 wxMessageBox(_("Sorry, an existing instance of OpenCPN may be too busy "
671 "to respond.\nPlease retry."),
672 "OpenCPN", wxICON_INFORMATION | wxOK);
673 m_exitcode = 2;
674 return true; // main program quiet exit.
675 }
676 if (client) {
677 auto result = client->HandleCmdline(m_parsed_cmdline.action,
678 m_parsed_cmdline.arg);
679 if (result.first) {
680 m_exitcode = 0;
681 } else {
682 wxLogDebug("Error running remote command: %s", result.second.c_str());
683 m_exitcode = 1;
684 }
685 return true;
686 }
687 }
688 }
689#endif // __ANDROID__
690
691 if (getenv("OPENCPN_FATAL_ERROR") != 0) {
692 wxLogFatalError(getenv("OPENCPN_FATAL_ERROR"));
693 }
694
695#ifndef __ANDROID__
696 // Check if last run failed, set up safe_mode.
697 if (!safe_mode::get_mode()) {
699 }
700#endif
701
702 // Perform first stage initialization
703 OCPNPlatform::Initialize_1();
704
705 // Set the name of the app as displayed to the user.
706 // This is necessary at least on OS X, for the capitalisation to be correct in
707 // the system menus.
708 MyApp::SetAppDisplayName("OpenCPN");
709
710 // Seed the random number generator
711 wxDateTime x = wxDateTime::UNow();
712 long seed = x.GetMillisecond();
713 seed *= x.GetTicks();
714 srand(seed);
715
716 // Fulup: force floating point to use dot as separation.
717 // This needs to be set early to catch numerics in config file.
718 setlocale(LC_NUMERIC, "C");
719
720 g_start_time = wxDateTime::Now();
721
722 g_loglast_time = g_start_time;
723 g_loglast_time.MakeGMT();
724 g_loglast_time.Subtract(
725 wxTimeSpan(0, 29, 0, 0)); // give 1 minute for GPS to get a fix
726
727 AnchorPointMinDist = 5.0;
728
729 // Init the private memory manager
730 malloc_max = 0;
731
732 // Record initial memory status
733 platform::GetMemoryStatus(&g_mem_total, &g_mem_initial);
734
735 // Set up default FONT encoding, which should have been done by wxWidgets some
736 // time before this......
737 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
738 wxFONTWEIGHT_NORMAL, FALSE, wxString(""),
739 wxFONTENCODING_SYSTEM);
740 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
741
742 // Start the Notification Manager and remove old persisted messages
743 auto &noteman = NotificationManager::GetInstance();
744 noteman.ScrubNotificationDirectory(30);
745
746 // Establish Log File location
747 if (!g_Platform->InitializeLogFile()) {
748 return false;
749 };
750
751#ifdef __WXMSW__
752
753 // Un-comment the following to establish a separate console window as a
754 // target for printf() in Windows RedirectIOToConsole();
755
756#endif
757
758 // Send init message
759 wxLogMessage("\n\n________\n");
760
761 wxDateTime now = wxDateTime::Now();
762 LOG_INFO("------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
763 now.FormatISODate().mb_str().data());
764 wxLogLevel level = wxLog::GetLogLevel();
765 LOG_INFO("Using loglevel %s", OcpnLog::level2str(level).c_str());
766
767 wxString wxver(wxVERSION_STRING);
768 wxver.Prepend("wxWidgets version: ");
769
770 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
771
772 wxString os_name;
773#ifndef __ANDROID__
774 os_name = platforminfo.GetOperatingSystemIdName();
775#else
776 os_name = platforminfo.GetOperatingSystemFamilyName();
777#endif
778
779 wxString platform = os_name + " " + platforminfo.GetArchName() + " " +
780 platforminfo.GetPortIdName();
781
782 wxLogMessage(wxver + " " + platform);
783
784 ::wxGetOsVersion(&osMajor, &osMinor);
785 wxString osVersionMsg;
786 osVersionMsg.Printf("OS Version reports as: %d.%d", osMajor, osMinor);
787 wxLogMessage(osVersionMsg);
788
789 wxLogMessage("MemoryStatus: mem_total: %d mb, mem_initial: %d mb",
790 g_mem_total / 1024, g_mem_initial / 1024);
791
792 OCPN_OSDetail *detail = g_Platform->GetOSDetail();
793 wxString msgplat;
794 wxString like0;
795 if (!detail->osd_names_like.empty())
796 like0 = detail->osd_names_like[0].c_str();
797 msgplat.Printf("OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
798 detail->osd_arch.c_str(), detail->osd_name.c_str(),
799 detail->osd_version.c_str(), detail->osd_ID.c_str(),
800 like0.mb_str());
801 wxLogMessage(msgplat);
802
803 wxString imsg = "SData_Locn is ";
804 imsg += g_Platform->GetSharedDataDir();
805 wxLogMessage(imsg);
806
807 // Initialize embedded PNG icon graphics
808 ::wxInitAllImageHandlers();
809
810#ifdef __WXQT__
811 // Now we can configure the Qt StyleSheets, if present
812 prepareAndroidStyleSheets();
813#endif
814
815 // Create some static strings
816 pInit_Chart_Dir = new wxString();
817
818 // Establish an empty ChartCroupArray
819 g_pGroupArray = new ChartGroupArray;
820
821 imsg = "PrivateDataDir is ";
822 imsg += g_Platform->GetPrivateDataDir();
823 wxLogMessage(imsg);
824
825 // Create an array string to hold repeating messages, so they don't
826 // overwhelm the log
827 navutil::InitGlobals();
828
829 // Init the Route Manager
831 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
832
833 // Init the Selectable Route Items List
834 pSelect = new Select();
835 pSelect->SetSelectPixelRadius(12);
836
837 // Init the Selectable Tide/Current Items List
838 pSelectTC = new Select();
839 // Increase the select radius for tide/current stations
840 pSelectTC->SetSelectPixelRadius(25);
841
842 // Init the Selectable AIS Target List
843 pSelectAIS = new Select();
844 pSelectAIS->SetSelectPixelRadius(12);
845
846 // Initially AIS display is always on
847 g_bShowAIS = true;
848 g_pais_query_dialog_active = NULL;
849
850 // Who am I?
851 g_hostname = ::wxGetHostName();
852 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
853#ifdef __ANDROID__
854 androidGetDeviceInfo();
855 g_hostname = wxString("Android-") + g_android_Device_Model;
856 g_hostname.Replace(" ", "-", true);
857#endif
858
859 // A Portabel need a unique mDNS data hostname to share routes.
860 if (g_bportable) {
861 wxString p("Portable-");
862 g_hostname = p + g_hostname;
863 }
864
865 // Initialize some lists
866 // Layers
867 pLayerList = new LayerList;
868 // Routes
869 pRouteList = new RouteList;
870
871 // Initialize the NavObj_db
872 auto &navobj_db = NavObj_dB::GetInstance();
873
874 // (Optionally) Capture the user and file(effective) ids
875 // Some build environments may need root privileges for hardware
876 // port I/O, as in the NMEA data input class. Set that up here.
877
878#ifndef __WXMSW__
879#ifdef PROBE_PORTS__WITH_HELPER
880 user_user_id = getuid();
881 file_user_id = geteuid();
882#endif
883#endif
884
885 bool b_initial_load = false;
886
887 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
888 if (config_test_file_name.FileExists())
889 wxLogMessage("Using existing Config_File: " +
890 g_Platform->GetConfigFileName());
891 else {
892 {
893 wxLogMessage("Creating new Config_File: " +
894 g_Platform->GetConfigFileName());
895
896 b_initial_load = true;
897
898 if (true !=
899 config_test_file_name.DirExists(config_test_file_name.GetPath()))
900 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
901 wxLogMessage("Cannot create config file directory for " +
902 g_Platform->GetConfigFileName());
903 }
904 }
905
906 // Open/Create the Config Object
907 pConfig = g_Platform->GetConfigObject();
908 InitBaseConfig(pConfig);
909 pConfig->LoadMyConfig();
910
911 if (g_kiosk_startup) {
912 g_wallpaper = new WallpaperFrame();
913 g_wallpaper->ShowFullScreen(true); // For a kiosk app, make it fullscreen
914 g_wallpaper->Show();
915 }
916
917 // Override for some safe and nice default values if the config file was
918 // created from scratch
919 if (b_initial_load) g_Platform->SetDefaultOptions();
920
921 g_Platform->applyExpertMode(g_bUIexpert);
922
923 // Now initialize UI Style.
924 g_StyleManager = new ocpnStyle::StyleManager();
925
926 g_StyleManager->SetStyle("MUI_flat");
927 if (!g_StyleManager->IsOK()) {
928 wxString msg = _("Failed to initialize the user interface. ");
929 msg << _("OpenCPN cannot start. ");
930 msg << _("The necessary configuration files were not found. ");
931 msg << _("See the log file at ") << g_Platform->GetLogFileName()
932 << _(" for details.") << "\n\n";
933 msg << g_Platform->GetSharedDataDir();
934
935 wxMessageDialog w(NULL, msg, _("Failed to initialize the user interface. "),
936 wxCANCEL | wxICON_ERROR);
937 w.ShowModal();
938 exit(EXIT_FAILURE);
939 }
940
941 if (g_useMUI) {
942 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
943 if (style) style->chartStatusWindowTransparent = true;
944 }
945
946 // Init the WayPoint Manager
947 pWayPointMan = NULL;
948
949 g_display_size_mm = wxMax(50, g_Platform->GetDisplaySizeMM());
950 wxString msg;
951 msg.Printf("Detected display size (horizontal): %d mm",
952 (int)g_display_size_mm);
953 wxLogMessage(msg);
954
955 // User override....
956 if (g_config_display_size_manual &&
960 wxString msg;
961 msg.Printf("Display size (horizontal) config override: %d mm",
962 (int)g_display_size_mm);
963 wxLogMessage(msg);
965 }
966
968
969 if (g_btouch) {
970 int SelectPixelRadius = 50;
971
972 pSelect->SetSelectPixelRadius(SelectPixelRadius);
973 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
974 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
975 }
976
977 // Is this the first run after a clean installation?
978 if (!n_NavMessageShown) {
979 g_bFirstRun = true;
980 }
981
982 // Now we can set the locale
983 // using wxWidgets/gettext methodology....
984
985#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
986
987 // Where are the opencpn.mo files?
988 g_Platform->SetLocaleSearchPrefixes();
989
990 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
991
992 imsg = "System default Language: " + def_lang_canonical;
993 wxLogMessage(imsg);
994
995 wxString cflmsg = "Config file language: " + g_locale;
996 wxLogMessage(cflmsg);
997
998 if (g_locale.IsEmpty()) {
999 g_locale = def_lang_canonical;
1000 cflmsg = "Config file language empty, using system default: " + g_locale;
1001 wxLogMessage(cflmsg);
1002 }
1003
1004 // Make any adjustments necessary
1005 g_locale = g_Platform->GetAdjustedAppLocale();
1006 cflmsg = "Adjusted App language: " + g_locale;
1007 wxLogMessage(cflmsg);
1008
1009 // Set the desired locale
1010 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1011
1012 imsg = "Opencpn language set to: ";
1013 imsg += g_locale;
1014 wxLogMessage(imsg);
1015
1016 // French language locale is assumed to include the AZERTY keyboard
1017 // This applies to either the system language, or to OpenCPN language
1018 // selection
1019 if (g_locale == "fr_FR") g_b_assume_azerty = true;
1020#else
1021 wxLogMessage("wxLocale support not available");
1022#endif
1023
1024#ifndef __ANDROID__
1025 // Now that locale is established, possibly run the startup wizard.
1026 if (g_config_wizard || b_initial_load) {
1027 FirstUseWizImpl wiz(gFrame, pConfig);
1028 auto res = wiz.Run();
1029 if (res) {
1030 g_NeedDBUpdate = 2;
1031 }
1032 }
1033#endif
1034
1035 // Instantiate and initialize the Config Manager
1036 ConfigMgr::Get();
1037
1038 // Is this an upgrade?
1039 wxString vs = wxString("Version ") + VERSION_FULL + " Build " + VERSION_DATE;
1040 g_bUpgradeInProcess = (vs != g_config_version_string);
1041
1042 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1043
1044 // log deferred log restart message, if it exists.
1045 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1046 wxLogMessage(g_Platform->GetLargeLogMessage());
1047 }
1048
1049 // Validate OpenGL functionality, if selected
1050#ifndef ocpnUSE_GL
1051 g_bdisable_opengl = true;
1052#endif
1053
1054 if (g_bdisable_opengl) g_bopengl = false;
1055
1056#if defined(__linux__) && !defined(__ANDROID__)
1057 if (g_bSoftwareGL) {
1058 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
1059 }
1060#endif
1061
1062 // FIXMW (dave) move to frame
1063 // g_bTransparentToolbarInOpenGLOK = isTransparentToolbarInOpenGLOK();
1064
1065 // On Windows platforms, establish a default cache managment policy
1066 // as allowing OpenCPN a percentage of available physical memory,
1067 // not to exceed 1 GB
1068 // Note that this logic implies that Windows platforms always use
1069 // the memCacheLimit policy, and never use the fallback nCacheLimit policy
1070#ifdef __WXMSW__
1071 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1072 g_memCacheLimit =
1073 wxMin(g_memCacheLimit, 1024 * 1024); // math in kBytes, Max is 1 GB
1074#else
1075 // All other platforms will use the nCacheLimit policy
1076 // sinc on linux it is impossible to accurately measure the application memory
1077 // footprint without expensive methods such as malloc/free tracking, and such
1078
1079 g_memCacheLimit = 0;
1080 if (0 == g_nCacheLimit) // allow config file override
1081 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1082#endif
1083
1084 // Establish location and name of chart database
1085 ChartListFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(),
1086 "chartlist.dat", "CHRTLIST.DAT");
1087
1088 // Establish location and name of AIS MMSI -> Target Name mapping
1089 AISTargetNameFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(),
1090 "mmsitoname.csv", "MMSINAME.CSV");
1091
1092 // Establish guessed location of chart tree
1093 if (pInit_Chart_Dir->IsEmpty()) {
1094 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1095
1096 if (!g_bportable)
1097#ifndef __ANDROID__
1098 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1099#else
1100 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1101#endif
1102 }
1103
1104 InitRestListeners();
1105
1106 // Establish the GSHHS Dataset location
1107 gDefaultWorldMapLocation = "gshhs";
1108 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1109 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1110 if (gWorldMapLocation == wxEmptyString) {
1111 gWorldMapLocation = gDefaultWorldMapLocation;
1112 }
1113
1114 // Check the global Tide/Current data source array
1115 // If empty, preset default (US + ROW) data sources
1116 wxString default_tcdata0 =
1117 (g_Platform->GetSharedDataDir() + "tcdata" +
1118 wxFileName::GetPathSeparator() + "harmonics-dwf-20210110-free.tcd");
1119 wxString default_tcdata1 =
1120 (g_Platform->GetSharedDataDir() + "tcdata" +
1121 wxFileName::GetPathSeparator() + "HARMONICS_NO_US.IDX");
1122
1123 if (TideCurrentDataSet.empty()) {
1124 TideCurrentDataSet.push_back(
1125 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1126 TideCurrentDataSet.push_back(
1127 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1128 }
1129
1130 // Check the global AIS alarm sound file
1131 // If empty, preset default
1132 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1133 wxString default_sound = (g_Platform->GetSharedDataDir() + "sounds" +
1134 wxFileName::GetPathSeparator() + "2bells.wav");
1135 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1136 }
1137
1138 gpIDXn = 0;
1139
1140 g_Platform->Initialize_2();
1141
1142 LoadChartDatabase();
1143
1144 // Kiosk startup mode only available in linux/GTK builds.
1145#ifndef __WXGTK__
1146 g_kiosk_startup = false;
1147#endif
1148
1149 // Create and initialize the main application frame.
1150 if (!g_kiosk_startup) {
1152 SetTopWindow(gFrame); // Set the main frame as the new top window.
1153 gFrame->Show();
1154 gFrame->Raise();
1155
1156 // Start delayed initialization chain after some milliseconds
1157 gFrame->InitTimer.Start(50, wxTIMER_CONTINUOUS);
1158
1159 } else {
1160 wxTheApp->CallAfter(&MyApp::OnMainFrameReady);
1161 }
1162
1163 OCPNPlatform::Initialize_4();
1164
1165#ifdef __ANDROID__
1166 androidHideBusyIcon();
1167#endif
1168 wxLogMessage(
1169 wxString::Format(_("OpenCPN Initialized in %ld ms."), init_sw.Time()));
1170
1171 wxMilliSleep(500);
1172
1173#ifdef __ANDROID__
1174 // We defer the startup message to here to allow the app frame to be
1175 // contructed, thus avoiding a dialog with NULL parent which might not work
1176 // on some devices.
1177 if (!n_NavMessageShown || (vs != g_config_version_string) ||
1178 (g_AndroidVersionCode != androidGetVersionCode())) {
1179 // qDebug() << "Showing NavWarning";
1180 wxMilliSleep(500);
1181
1182 if (!ShowNavWarning()) {
1183 qDebug() << "Closing due to NavWarning Cancel";
1184 gFrame->Close();
1185 androidTerminate();
1186 return true;
1187 }
1188
1189 n_NavMessageShown = 1;
1190 }
1191
1192 // Finished with upgrade checking, so persist the currect Version Code
1193 g_AndroidVersionCode = androidGetVersionCode();
1194 qDebug() << "Persisting Version Code: " << g_AndroidVersionCode;
1195#else
1196 // Send the Welcome/warning message if it has never been sent before,
1197 // or if the version string has changed at all
1198 // We defer until here to allow for localization of the message
1199 if (!n_NavMessageShown || (vs != g_config_version_string)) {
1200 if (!ShowNavWarning()) return false;
1201 n_NavMessageShown = 1;
1202 pConfig->Flush();
1203 }
1204#endif
1205
1206 // As an a.e. Raspberry does not have a hardwareclock we will have some
1207 // problems with date/time setting
1208 g_bHasHwClock = true; // by default most computers do have a hwClock
1209#if defined(__UNIX__) && !defined(__ANDROID__)
1210 struct stat buffer;
1211 g_bHasHwClock =
1212 ((stat("/dev/rtc", &buffer) == 0) || (stat("/dev/rtc0", &buffer) == 0) ||
1213 (stat("/dev/misc/rtc", &buffer) == 0));
1214#endif
1215
1216 g_config_version_string = vs;
1217
1218 // The user accepted the "not for navigation" nag, so persist it here...
1219 pConfig->UpdateSettings();
1220
1221 for (auto *cp : TheConnectionParams()) {
1222 if (cp->bEnabled) {
1223 if (cp->GetDSPort().Contains("Serial")) {
1224 std::string port(cp->Port.ToStdString());
1226 }
1227 }
1228 }
1230
1231 // Initialize the CommBridge
1232 m_comm_bridge.Initialize();
1233
1234 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1235
1236 // If network connection is available, start the server and mDNS client
1237 if (ipv4_addrs.size()) {
1238 std::string ipAddr = ipv4_addrs[0];
1239
1240 wxString data_dir = g_Platform->GetPrivateDataDir();
1241 if (data_dir.Last() != wxFileName::GetPathSeparator())
1242 data_dir.Append(wxFileName::GetPathSeparator());
1243
1244 make_certificate(ipAddr, data_dir.ToStdString());
1245
1246 m_rest_server.StartServer(fs::path(data_dir.ToStdString()));
1247 StartMDNSService(g_hostname.ToStdString(), "opencpn-object-control-service",
1248 8000);
1249 }
1250 return TRUE;
1251}
1252
1255 gFrame->Hide();
1256
1257 // Hide the old frame and show the new one.
1258 g_wallpaper->Show(false);
1260
1261 gFrame->ShowFullScreen(true);
1262
1263 // Cleanup the wallpaper frame.
1264 g_wallpaper->Destroy();
1265 g_wallpaper = nullptr;
1266
1267 SetTopWindow(gFrame); // Set the main frame as the new top window.
1268 gFrame->Raise();
1269
1270 // Start delayed initialization chain after some milliseconds
1271 gFrame->InitTimer.Start(50, wxTIMER_CONTINUOUS);
1272}
1273
1275 // Set up the frame initial visual parameters
1276 // Default size, resized later
1277 wxSize new_frame_size(-1, -1);
1278 int cx, cy, cw, ch;
1279 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1280
1281 InitializeUserColors();
1282
1283 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1284 (g_nframewin_y <= ch))
1285 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1286 else
1287 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1288
1289 // Try to detect any change in physical screen configuration
1290 // This can happen when drivers are changed, for instance....
1291 // and can confuse the WUI layout perspective stored in the config file.
1292 // If detected, force a nominal window size and position....
1293 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1294 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1295 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1296 g_bframemax = false;
1297 }
1298
1299 g_lastClientRectx = cx;
1300 g_lastClientRecty = cy;
1301 g_lastClientRectw = cw;
1302 g_lastClientRecth = ch;
1303
1304 // Validate config file position
1305 wxPoint position(0, 0);
1306 wxSize dsize = wxGetDisplaySize();
1307
1308#ifdef __WXMAC__
1309 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1310#endif
1311
1312 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1313 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1314
1315#ifdef __WXMSW__
1316 // Support MultiMonitor setups which can allow negative window positions.
1317 RECT frame_rect;
1318 frame_rect.left = position.x;
1319 frame_rect.top = position.y;
1320 frame_rect.right = position.x + new_frame_size.x;
1321 frame_rect.bottom = position.y + new_frame_size.y;
1322
1323 // If the requested frame window does not intersect any installed monitor,
1324 // then default to simple primary monitor positioning.
1325 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1326 position = wxPoint(10, 10);
1327#endif
1328
1329#ifdef __WXOSX__
1330 // Support MultiMonitor setups which can allow negative window positions.
1331 const wxPoint ptScreen(position.x, position.y);
1332 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1333
1334 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1335#endif
1336
1337 g_nframewin_posx = position.x;
1338 g_nframewin_posy = position.y;
1339
1340#ifdef __ANDROID__
1341 wxSize asz = getAndroidDisplayDimensions();
1342 ch = asz.y;
1343 cw = asz.x;
1344 // qDebug() << cw << ch;
1345
1346 if ((cw > 200) && (ch > 200))
1347 new_frame_size.Set(cw, ch);
1348 else
1349 new_frame_size.Set(800, 400);
1350#endif
1351
1352 // For Windows and GTK, provide the expected application Minimize/Close bar
1353 long app_style = wxDEFAULT_FRAME_STYLE;
1354 app_style |= wxWANTS_CHARS;
1355
1356 // Create the main frame window
1357
1358 // Strip the commit SHA number from the string to be shown in frame title.
1359 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst('+');
1360 wxString myframe_window_title = wxString("OpenCPN " + short_version_name);
1361
1362 if (g_bportable) {
1363 myframe_window_title += _(" -- [Portable(-p) executing from ");
1364 myframe_window_title += g_Platform->GetHomeDir();
1365 myframe_window_title += "]";
1366 }
1367
1368 wxString fmsg;
1369 fmsg.Printf("Creating MyFrame...size(%d, %d) position(%d, %d)",
1370 new_frame_size.x, new_frame_size.y, position.x, position.y);
1371 wxLogMessage(fmsg);
1372
1374 auto dockart = new wxAuiDefaultDockArt;
1375 g_pauimgr->SetArtProvider(dockart);
1376
1377 gFrame = new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1378 app_style, dockart);
1379
1380 // Initialize the Plugin Manager
1381 g_pi_manager = new PlugInManager(gFrame);
1382
1383 g_pauimgr->SetDockSizeConstraint(.9, .9);
1384
1385 // tell wxAuiManager to manage the frame
1386 g_pauimgr->SetManagedWindow(gFrame);
1387
1388 // Do those platform specific initialization things that need gFrame
1389 g_Platform->Initialize_3();
1390
1391 gFrame->CreateCanvasLayout();
1392
1393 // gFrame->RequestNewMasterToolbar( true );
1394
1395 gFrame->SetChartUpdatePeriod(); // Reasonable default
1396
1397 pthumbwin = new ThumbWin(gFrame->GetPrimaryCanvas());
1398
1399 gFrame->ApplyGlobalSettings(false); // done once on init with resize
1400 gFrame->SetAllToolbarScale();
1401 gFrame->SetAndApplyColorScheme(global_color_scheme);
1402 if (g_bframemax) gFrame->Maximize(true);
1403
1404#ifdef __ANDROID__
1405 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->GetPixPerMM() > 4.0))
1406 gFrame->Maximize(true);
1407#endif
1408
1409 // All set to go.....
1410
1411 // Process command line option to rebuild cache
1412#ifdef ocpnUSE_GL
1413 extern ocpnGLOptions g_GLOptions;
1414
1415 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1416 g_GLOptions.m_bTextureCompressionCaching) {
1417 gFrame->ReloadAllVP(); // Get a nice chart background loaded
1418
1419 // Turn off the toolbar as a clear signal that the system is busy right
1420 // now.
1421 // Note: I commented this out because the toolbar never comes back for me
1422 // and is unusable until I restart opencpn without generating the cache
1423 // if( g_MainToolbar )
1424 // g_MainToolbar->Hide();
1425
1426 if (g_glTextureManager) g_glTextureManager->BuildCompressedCache();
1427 }
1428#endif
1429
1430 // FIXME (dave)
1431 // move method to frame
1432 // if (g_parse_all_enc) ParseAllENC(gFrame);
1433
1434 // establish GPS timeout value as multiple of frame timer
1435 // This will override any nonsense or unset value from the config file
1436 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1437 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1438
1439 wxString dogmsg;
1440 dogmsg.Printf("GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1441 wxLogMessage(dogmsg);
1442
1443 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1444
1445 g_priSats = 99;
1446
1447 // Most likely installations have no ownship heading information
1448 g_bVAR_Rx = false;
1449
1450 // Start up a new track if enabled in config file
1451 if (g_bTrackCarryOver) g_bDeferredStartTrack = true;
1452
1453 pAnchorWatchPoint1 = NULL;
1454 pAnchorWatchPoint2 = NULL;
1455
1456 gFrame->DoChartUpdate();
1457
1458 // Load and initialize plugins
1459 auto style = g_StyleManager->GetCurrentStyle();
1460 auto bitmap = new wxBitmap(style->GetIcon("default_pi", 32, 32));
1461 if (bitmap->IsOk())
1462 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1463 else
1464 wxLogWarning("Cannot initiate plugin default jigsaw icon.");
1465
1467 PluginLoader::GetInstance()->LoadAllPlugIns(true);
1469
1470 // A Plugin (e.g. Squiddio) may have redefined some routepoint icons...
1471 // Reload all icons, to be sure.
1473
1474 wxString perspective;
1475 pConfig->SetPath("/AUI");
1476 pConfig->Read("AUIPerspective", &perspective);
1477
1478 // Make sure the perspective saved in the config file is "reasonable"
1479 // In particular, the perspective should have an entry for every
1480 // windows added to the AUI manager so far.
1481 // If any are not found, then use the default layout
1482
1483 bool bno_load = false;
1484
1485 wxArrayString name_array;
1486 wxStringTokenizer st(perspective, "|;");
1487 while (st.HasMoreTokens()) {
1488 wxString s1 = st.GetNextToken();
1489 if (s1.StartsWith("name=")) {
1490 wxString sc = s1.AfterFirst('=');
1491 name_array.Add(sc);
1492 }
1493 }
1494
1495 wxAuiPaneInfoArray pane_array_val = g_pauimgr->GetAllPanes();
1496 for (unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1497 wxAuiPaneInfo pane = pane_array_val.Item(i);
1498
1499 // If we find a pane that is not in the perspective,
1500 // then we should not load the perspective at all
1501 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1502 bno_load = true;
1503 break;
1504 }
1505 }
1506
1507 if (!bno_load) g_pauimgr->LoadPerspective(perspective, false);
1508
1509 // Touch up the AUI manager
1510 // Make sure that any pane width is reasonable default value
1511#if 0 // TODO nees this?
1512 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1513 ChartCanvas *cc = g_canvasArray.Item(i);
1514 if (cc) {
1515 wxSize frameSize = GetClientSize();
1516 wxSize minSize = g_pauimgr->GetPane(cc).min_size;
1517 int width = wxMax(minSize.x, frameSize.x / 10);
1518 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1519 }
1520 }
1521 g_pauimgr->Update();
1522#endif
1523 g_pauimgr->Update();
1524
1525 // Notify all the AUI PlugIns so that they may syncronize with the
1526 // Perspective
1527 g_pi_manager->NotifyAuiPlugIns();
1528
1529 // Give the user dialog on any blacklisted PlugIns
1530 g_pi_manager->ShowDeferredBlacklistMessages();
1531 g_pi_manager->CallLateInit();
1532
1533 return;
1534
1535 gFrame->DoChartUpdate();
1536
1537 FontMgr::Get()
1538 .ScrubList(); // Clean the font list, removing nonsensical entries
1539
1540 gFrame->ReloadAllVP(); // once more, and good to go
1541
1542 gFrame->Refresh(false);
1543 gFrame->Raise();
1544
1545 gFrame->GetPrimaryCanvas()->Enable();
1546 gFrame->GetPrimaryCanvas()->SetFocus();
1547
1548 // This little hack fixes a problem seen with some UniChrome OpenGL drivers
1549 // We need a deferred resize to get glDrawPixels() to work right.
1550 // So we set a trigger to generate a resize after 5 seconds....
1551 // See the "UniChrome" hack elsewhere
1552#ifdef ocpnUSE_GL
1553 if (!g_bdisable_opengl) {
1554 glChartCanvas *pgl =
1555 (glChartCanvas *)gFrame->GetPrimaryCanvas()->GetglCanvas();
1556 if (pgl && (pgl->GetRendererString().Find("UniChrome") != wxNOT_FOUND)) {
1557 gFrame->m_defer_size = gFrame->GetSize();
1558 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1559 g_pauimgr->Update();
1560 gFrame->m_bdefer_resize = true;
1561 }
1562 }
1563#endif
1564
1565 // Horrible Hack (tm): Make sure the RoutePoint destructor can invoke
1566 // glDeleteTextures. Truly awful.
1567#ifdef ocpnUSE_GL
1568 if (g_bopengl)
1569 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {
1570 glDeleteTextures(n, texts);
1571 };
1572#else
1573 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {};
1574#endif
1575
1576 if (g_start_fullscreen) gFrame->ToggleFullScreen();
1577
1578#ifdef __ANDROID__
1579 // We need a resize to pick up height adjustment after building android
1580 // ActionBar
1581 gFrame->SetSize(getAndroidDisplayDimensions());
1582 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1583#endif
1584
1586 gFrame->GetPrimaryCanvas()->Enable();
1587 gFrame->GetPrimaryCanvas()->SetFocus();
1588
1589 // Setup Tides/Currents to settings present at last shutdown
1590 // TODO
1591 // gFrame->ShowTides( g_bShowTide );
1592 // gFrame->ShowCurrents( g_bShowCurrent );
1593
1594 // wxLogMessage( wxString::Format("OpenCPN Initialized in %ld ms.",
1595 // init_sw.Time() ) );
1596}
1597
1598void MyApp::LoadChartDatabase() {
1599 // Build the initial chart dir array
1600 ArrayOfCDI ChartDirArray;
1601 pConfig->LoadChartDirArray(ChartDirArray);
1602
1603 // Windows installer may have left hints regarding the initial chart dir
1604 // selection
1605#ifdef __WXMSW__
1606 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1607 int ndirs = 0;
1608
1609 wxRegKey RegKey(wxString("HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1610 if (RegKey.Exists()) {
1611 wxLogMessage(
1612 _("Retrieving initial Chart Directory set from Windows Registry"));
1613 wxString dirs;
1614 RegKey.QueryValue(wxString("ChartDirs"), dirs);
1615
1616 wxStringTokenizer tkz(dirs, ";");
1617 while (tkz.HasMoreTokens()) {
1618 wxString token = tkz.GetNextToken();
1619
1620 ChartDirInfo cdi;
1621 cdi.fullpath = token.Trim();
1622 cdi.magic_number = "";
1623
1624 ChartDirArray.Add(cdi);
1625 ndirs++;
1626 }
1627 }
1628
1629 if (g_bportable) {
1630 ChartDirInfo cdi;
1631 cdi.fullpath = "charts";
1632 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1633 cdi.magic_number = "";
1634 ChartDirArray.Add(cdi);
1635 ndirs++;
1636 }
1637
1638 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1639 }
1640#endif
1641
1642 // If the ChartDirArray is empty at this point, any existing chart database
1643 // file must be declared invalid, So it is best to simply delete it if
1644 // present.
1645 // TODO There is a possibility of recreating the dir list from the
1646 // database itself......
1647
1648 if (!ChartDirArray.GetCount())
1649 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1650
1651 // Try to load the current chart list Data file
1652 ChartData = new ChartDB();
1653 if (g_NeedDBUpdate == 0 &&
1654 !ChartData->LoadBinary(ChartListFileName, ChartDirArray)) {
1655 g_NeedDBUpdate = 1;
1656 }
1657
1658 // Verify any saved chart database startup index
1659 if (g_restore_dbindex >= 0) {
1660 if (ChartData->GetChartTableEntries() == 0)
1661 g_restore_dbindex = -1;
1662
1663 else if (g_restore_dbindex > (ChartData->GetChartTableEntries() - 1))
1664 g_restore_dbindex = 0;
1665 }
1666
1667 // Apply the inital Group Array structure to the chart database
1668 ChartData->ApplyGroupArray(g_pGroupArray);
1669}
1670
1672 wxLogMessage("opencpn::MyApp starting exit.");
1673 m_checker.OnExit();
1674 m_usb_watcher.Stop();
1675 // Send current nav status data to log file // pjotrc 2010.02.09
1676
1677 wxDateTime lognow = wxDateTime::Now();
1678 lognow.MakeGMT();
1679 wxString day = lognow.FormatISODate();
1680 wxString utc = lognow.FormatISOTime();
1681 wxString navmsg = "LOGBOOK: ";
1682 navmsg += day;
1683 navmsg += " ";
1684 navmsg += utc;
1685 navmsg += " UTC ";
1686
1687 if (bGPSValid) {
1688 wxString data;
1689 data.Printf("OFF: Lat %10.5f Lon %10.5f ", gLat, gLon);
1690 navmsg += data;
1691
1692 wxString cog;
1693 if (std::isnan(gCog))
1694 cog.Printf("COG ----- ");
1695 else
1696 cog.Printf("COG %10.5f ", gCog);
1697
1698 wxString sog;
1699 if (std::isnan(gSog))
1700 sog.Printf("SOG ----- ");
1701 else
1702 sog.Printf("SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(gSog));
1703
1704 navmsg += cog;
1705 navmsg += sog;
1706
1707 } else {
1708 wxString data;
1709 data.Printf("OFF: Lat %10.5f Lon %10.5f", gLat, gLon);
1710 navmsg += data;
1711 }
1712 wxLogMessage(navmsg);
1713 g_loglast_time = lognow;
1714
1715 if (ptcmgr) delete ptcmgr;
1716
1717 for (Track *track : g_TrackList) {
1718 delete track;
1719 }
1720 g_TrackList.clear();
1721
1722 delete pConfig;
1723 delete pSelect;
1724 delete pSelectTC;
1725 delete pSelectAIS;
1726
1727 delete ps52plib;
1728 delete g_SencThreadManager;
1729
1730 if (g_pGroupArray) {
1731 for (unsigned int igroup = 0; igroup < g_pGroupArray->GetCount();
1732 igroup++) {
1733 delete g_pGroupArray->Item(igroup);
1734 }
1735
1736 g_pGroupArray->Clear();
1737 delete g_pGroupArray;
1738 }
1739
1740 wxLogMessage("opencpn::MyApp exiting cleanly...\n");
1741 wxLog::FlushActive();
1742
1743 g_Platform->CloseLogFile();
1744
1745 delete pInit_Chart_Dir;
1746
1747 for (Track *track : g_TrackList) {
1748 delete track;
1749 }
1750 g_TrackList.clear();
1751
1752 delete g_pRouteMan;
1753 delete pWayPointMan;
1754
1755 navutil::DeinitGlobals();
1756
1757 DeInitializeUserColors();
1758
1759 delete pLayerList;
1760
1761 delete m_pRegistrarMan;
1762 CSVDeaccess(NULL);
1763
1764 delete g_StyleManager;
1765
1766 // Restore any changed system colors
1767
1768#ifdef __WXMSW__
1769 void RestoreSystemColors();
1770 RestoreSystemColors();
1771#endif
1772
1773#ifdef __MSVC__LEAK
1774 DeInitAllocCheck();
1775#endif
1776
1777#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1779#endif
1780
1781 FontMgr::Shutdown();
1782
1783 g_Platform->OnExit_2();
1785 delete g_Platform;
1786
1787 return TRUE;
1788}
1789
1790#ifdef LINUX_CRASHRPT
1791void MyApp::OnFatalException() { g_crashprint.Report(); }
1792#endif
1793
1794//----------------------------------------------------------------------------------------------------------
1795// Application-wide CPL Error handler
1796//----------------------------------------------------------------------------------------------------------
1797void MyCPLErrorHandler(CPLErr eErrClass, int nError, const char *pszErrorMsg)
1798
1799{
1800 char msg[256];
1801
1802 if (eErrClass == CE_Debug)
1803 snprintf(msg, 255, "CPL: %s", pszErrorMsg);
1804 else if (eErrClass == CE_Warning)
1805 snprintf(msg, 255, "CPL Warning %d: %s", nError, pszErrorMsg);
1806 else
1807 snprintf(msg, 255, "CPL ERROR %d: %s", nError, pszErrorMsg);
1808
1809 wxString str(msg, wxConvUTF8);
1810 wxLogMessage(str);
1811}
class About
Class AboutFrameImpl.
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.
BasePlatform * g_BasePlatform
points to g_platform, handles brain-dead MS linker.
Chart canvas configuration state
Purpose: TLS Certificate support.
ChartDB * ChartData
Global instance.
Definition chartdb.cpp:70
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Definition chartdbs.cpp:56
Generic Chart canvas base.
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
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.
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:157
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
Definition chcanv.h:515
Manages the chart database and provides access to chart data.
Definition chartdb.h:95
bool LoadBinary(const wxString &filename, ArrayOfCDI &dir_array_check)
Load the chart database from a binary file.
Definition chartdb.cpp:229
void Notify() override
Notify all listeners, no data supplied.
void ScrubList()
Cleans up stale font entries after a locale change.
Definition font_mgr.cpp:555
static void SeedRandom()
Seed the random generator used by GetUUID().
Common interface for all instance checkers.
virtual bool IsMainInstance()=0
Return true if this process is the primary opencpn instance.
virtual void CleanUp()
Remove all persistent instance state, including possible lock file and defunct opencpn processes.
virtual void OnExit()
Do whatever needed before wxWidget's checks triggers.
virtual void WaitUntilValid()
Wait until this object can be used for example for Dbus connection.
static LocalServerApi & GetInstance()
void BuildMainFrame()
bool OnInit() override
Definition ocpn_app.cpp:619
void OnMainFrameReady()
int OnExit() override
Main application frame.
Definition ocpn_frame.h:139
Provides platform-specific support utilities for OpenCPN.
void SetDisplaySizeMM(size_t monitor, double size)
Set the width of the monitor in millimeters.
double GetDisplaySizeMM()
Get the width of the screen in millimeters.
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
Definition observable.h:295
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.
Definition route_point.h:71
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Definition route_point.h:47
Represents a navigational route in the navigation system.
Definition route.h:99
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
Definition route.h:203
wxString m_RouteNameString
User-assigned name for the route.
Definition route.h:247
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
Definition routeman.h:265
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Definition routeman.cpp:222
Window for displaying chart thumbnails.
Definition thumbwin.h:47
Represents a track, which is a series of connected track points.
Definition track.h:117
Listen to hardware events and notifies SystemEvents when new devices are plugged in.
OpenGL chart rendering canvas.
Handles crash reporting in wxWidgets applications.
Definition crashprint.h:24
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
CommBridge class and helpers.
NMEA Data Multiplexer Object.
Variables maintained by comm stack, read-only access for others.
Primary navigation console display for route and vessel tracking.
Config file user configuration interface.
std::vector< size_t > g_config_display_size_mm
Size of pysical screen in millimeters.
double g_display_size_mm
Physical display width (mm)
Global variables stored in configuration file.
Dump debug info on crash.
Chart display details slider.
Font list manager.
NMEA Data Object.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture cache.
Go to position dialog...
size_t g_current_monitor
Current monitor displaying main application frame.
Definition gui_vars.cpp:75
int g_NeedDBUpdate
0 - No update needed, 1 - Update needed because there is no chart database, inform user 2 - Start upd...
Definition gui_vars.cpp:94
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Instance check interface.
Chart object layer.
The local API has a server side handling commands and a client part issuing commands.
Enhanced logging interface on top of wx/log.h.
MacOS hardware probing functions.
Waypoint properties maintenance dialog.
mDNS lookup wrappers.
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.
Definition safe_mode.cpp:62
MySQL based storage for routes, tracks, etc.
Utility functions.
Navigation Utility Functions without GUI dependencies.
User notifications manager.
s57RegistrarMgr * m_pRegistrarMan
Global instance.
Definition o_senc.cpp:62
S57 SENC File Object.
General observable implementation with several specializations.
OpenCPN main program.
OCPN_AUIManager * g_pauimgr
Global instance.
OCPN_AUIManager.
OpenCPN top window.
OpenCPN Platform specific support utilities.
Options dialog.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
Definition own_ship.cpp:34
double gLat
Vessel's current latitude in decimal degrees.
Definition own_ship.cpp:26
double gCog
Course over ground in degrees (0-359.99).
Definition own_ship.cpp:28
double gSog
Speed over ground in knots.
Definition own_ship.cpp:29
double gLon
Vessel's current longitude in decimal degrees.
Definition own_ship.cpp:27
Position, course, speed, etc.
Plugin remote repositories installation and Uninstall/list operations.
PlugInManager * g_pi_manager
Global instance.
REST server dialogs.
Route abstraction.
Route properties dialog.
RoutePoint * pAnchorWatchPoint2
Global instance.
Definition routeman.cpp:64
Routeman * g_pRouteMan
Global instance.
Definition routeman.cpp:60
RouteList * pRouteList
Global instance.
Definition routeman.cpp:66
RoutePoint * pAnchorWatchPoint1
Global instance.
Definition routeman.cpp:63
Route Manager.
Routeman drawing stuff.
Manage routes dialog.
S57 object query result window.
S57 Chart Object.
Select * pSelect
Global instance.
Definition select.cpp:36
Select * pSelectTC
Global instance.
Definition select.cpp:37
Selected route, segment, waypoint, etc.
SENCThreadManager * g_SencThreadManager
Global instance.
Chart Symbols.
TCMgr * ptcmgr
Global instance.
Definition tcmgr.cpp:42
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
Definition thumbwin.cpp:40
Chart thumbnail object.
std::vector< Track * > g_TrackList
Global instance.
Definition track.cpp:96
Recorded track abstraction.
Track Properties Dialog.
Access checks for comm devices and dongle.