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