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->SetGPSCompassScale();
1480
1481 // gFrame->RequestNewMasterToolbar( true );
1482
1483 gFrame->SetChartUpdatePeriod(); // Reasonable default
1484
1485 pthumbwin = new ThumbWin(gFrame->GetPrimaryCanvas());
1486
1487 gFrame->ApplyGlobalSettings(false); // done once on init with resize
1488 gFrame->SetAllToolbarScale();
1489 gFrame->SetAndApplyColorScheme(global_color_scheme);
1490 if (g_bframemax) gFrame->Maximize(true);
1491
1492#ifdef __ANDROID__
1493 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->GetPixPerMM() > 4.0))
1494 gFrame->Maximize(true);
1495#endif
1496
1497 // All set to go.....
1498
1499 // Process command line option to rebuild cache
1500#ifdef ocpnUSE_GL
1501 extern ocpnGLOptions g_GLOptions;
1502
1503 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1504 g_GLOptions.m_bTextureCompressionCaching) {
1505 gFrame->ReloadAllVP(); // Get a nice chart background loaded
1506
1507 // Turn off the toolbar as a clear signal that the system is busy right
1508 // now.
1509 // Note: I commented this out because the toolbar never comes back for me
1510 // and is unusable until I restart opencpn without generating the cache
1511 // if( g_MainToolbar )
1512 // g_MainToolbar->Hide();
1513
1514 if (g_glTextureManager) g_glTextureManager->BuildCompressedCache();
1515 }
1516#endif
1517
1518 // FIXME (dave)
1519 // move method to frame
1520 // if (g_parse_all_enc) ParseAllENC(gFrame);
1521
1522 // establish GPS timeout value as multiple of frame timer
1523 // This will override any nonsense or unset value from the config file
1524 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1525 gps_watchdog_timeout_ticks = (kGpsTimeoutSeconds * 1000) / TIMER_GFRAME_1;
1526
1527 wxString dogmsg;
1528 dogmsg.Printf("GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1529 wxLogMessage(dogmsg);
1530
1531 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1532
1533 g_priSats = 99;
1534
1535 // Most likely installations have no ownship heading information
1536 g_bVAR_Rx = false;
1537
1538 // Start up a new track if enabled in config file
1539 if (g_bTrackCarryOver) g_bDeferredStartTrack = true;
1540
1541 pAnchorWatchPoint1 = NULL;
1542 pAnchorWatchPoint2 = NULL;
1543
1544 gFrame->DoChartUpdate();
1545
1546 // Load comm connections
1547 for (auto *cp : TheConnectionParams()) {
1548 if (cp->bEnabled) {
1549 MakeCommDriver(cp);
1550 cp->b_IsSetup = TRUE;
1551 }
1552 }
1554
1555 // Load and initialize plugins
1556 auto style = g_StyleManager->GetCurrentStyle();
1557 auto bitmap = new wxBitmap(style->GetIcon("default_pi", 32, 32));
1558 if (bitmap->IsOk())
1559 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1560 else
1561 wxLogWarning("Cannot initiate plugin default jigsaw icon.");
1562
1563 AbstractPlatform::ShowBusySpinner();
1564 PluginLoader::GetInstance()->LoadAllPlugIns(true);
1565 AbstractPlatform::HideBusySpinner();
1566
1567 if (g_kiosk_startup) g_pi_manager->CallLateInit();
1568
1569 wxString perspective;
1570 pConfig->SetPath("/AUI");
1571 pConfig->Read("AUIPerspective", &perspective);
1572
1573 // Make sure the perspective saved in the config file is "reasonable"
1574 // In particular, the perspective should have an entry for every
1575 // windows added to the AUI manager so far.
1576 // If any are not found, then use the default layout
1577
1578 bool bno_load = false;
1579
1580 wxArrayString name_array;
1581 wxStringTokenizer st(perspective, "|;");
1582 while (st.HasMoreTokens()) {
1583 wxString s1 = st.GetNextToken();
1584 if (s1.StartsWith("name=")) {
1585 wxString sc = s1.AfterFirst('=');
1586 name_array.Add(sc);
1587 }
1588 }
1589
1590 wxAuiPaneInfoArray pane_array_val = g_pauimgr->GetAllPanes();
1591 for (unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1592 wxAuiPaneInfo pane = pane_array_val.Item(i);
1593
1594 // If we find a pane that is not in the perspective,
1595 // then we should not load the perspective at all
1596 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1597 bno_load = true;
1598 break;
1599 }
1600 }
1601
1602 if (!bno_load) g_pauimgr->LoadPerspective(perspective, false);
1603
1604 // Touch up the AUI manager
1605 // Make sure that any pane width is reasonable default value
1606#if 0 // TODO nees this?
1607 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1608 ChartCanvas *cc = g_canvasArray.Item(i);
1609 if (cc) {
1610 wxSize frameSize = GetClientSize();
1611 wxSize minSize = g_pauimgr->GetPane(cc).min_size;
1612 int width = wxMax(minSize.x, frameSize.x / 10);
1613 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1614 }
1615 }
1616 g_pauimgr->Update();
1617#endif
1618 g_pauimgr->Update();
1619
1620 // Notify all the AUI PlugIns so that they may syncronize with the
1621 // Perspective
1622 g_pi_manager->NotifyAuiPlugIns();
1623
1624 // Give the user dialog on any blacklisted PlugIns
1625 g_pi_manager->ShowDeferredBlacklistMessages();
1626 // g_pi_manager->CallLateInit();
1627
1628 return;
1629
1630 // This little hack fixes a problem seen with some UniChrome OpenGL drivers
1631 // We need a deferred resize to get glDrawPixels() to work right.
1632 // So we set a trigger to generate a resize after 5 seconds....
1633 // See the "UniChrome" hack elsewhere
1634#ifdef ocpnUSE_GL
1635 if (!g_bdisable_opengl) {
1636 glChartCanvas *pgl =
1637 (glChartCanvas *)gFrame->GetPrimaryCanvas()->GetglCanvas();
1638 if (pgl && (pgl->GetRendererString().Find("UniChrome") != wxNOT_FOUND)) {
1639 gFrame->m_defer_size = gFrame->GetSize();
1640 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1641 g_pauimgr->Update();
1642 gFrame->m_bdefer_resize = true;
1643 }
1644 }
1645#endif
1646
1647 // Horrible Hack (tm): Make sure the RoutePoint destructor can invoke
1648 // glDeleteTextures. Truly awful.
1649#ifdef ocpnUSE_GL
1650 if (g_bopengl)
1651 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {
1652 glDeleteTextures(n, texts);
1653 };
1654#else
1655 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {};
1656#endif
1657
1658#ifdef __ANDROID__
1659 // We need a resize to pick up height adjustment after building android
1660 // ActionBar
1661 gFrame->SetSize(getAndroidDisplayDimensions());
1662 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1663#endif
1664
1665 // Setup Tides/Currents to settings present at last shutdown
1666 // TODO
1667 // gFrame->ShowTides( g_bShowTide );
1668 // gFrame->ShowCurrents( g_bShowCurrent );
1669
1670 // wxLogMessage( wxString::Format("OpenCPN Initialized in %ld ms.",
1671 // init_sw.Time() ) );
1672}
1673
1674void MyApp::LoadChartDatabase() {
1675 // Build the initial chart dir array
1676 ArrayOfCDI ChartDirArray;
1677 pConfig->LoadChartDirArray(ChartDirArray);
1678
1679 // Windows installer may have left hints regarding the initial chart dir
1680 // selection
1681#ifdef __WXMSW__
1682 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1683 int ndirs = 0;
1684
1685 wxRegKey RegKey(wxString("HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1686 if (RegKey.Exists()) {
1687 wxLogMessage(
1688 _("Retrieving initial Chart Directory set from Windows Registry"));
1689 wxString dirs;
1690 RegKey.QueryValue(wxString("ChartDirs"), dirs);
1691
1692 wxStringTokenizer tkz(dirs, ";");
1693 while (tkz.HasMoreTokens()) {
1694 wxString token = tkz.GetNextToken();
1695
1696 ChartDirInfo cdi;
1697 cdi.fullpath = token.Trim();
1698 cdi.magic_number = "";
1699
1700 ChartDirArray.Add(cdi);
1701 ndirs++;
1702 }
1703 }
1704
1705 if (g_bportable) {
1706 ChartDirInfo cdi;
1707 cdi.fullpath = "charts";
1708 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1709 cdi.magic_number = "";
1710 ChartDirArray.Add(cdi);
1711 ndirs++;
1712 }
1713
1714 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1715 }
1716#endif
1717
1718 // If the ChartDirArray is empty at this point, any existing chart database
1719 // file must be declared invalid, So it is best to simply delete it if
1720 // present.
1721 // TODO There is a possibility of recreating the dir list from the
1722 // database itself......
1723
1724 if (!ChartDirArray.GetCount())
1725 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1726
1727 // Try to load the current chart list Data file
1728 ChartData = new ChartDB();
1729 if (g_NeedDBUpdate == 0 &&
1730 !ChartData->LoadBinary(ChartListFileName, ChartDirArray)) {
1731 g_NeedDBUpdate = 1;
1732 g_restore_dbindex = 0;
1733 }
1734
1735 // Verify any saved chart database startup index
1736 if (g_restore_dbindex >= 0) {
1737 if (ChartData->GetChartTableEntries() == 0)
1738 g_restore_dbindex = -1;
1739
1740 else if (g_restore_dbindex > (ChartData->GetChartTableEntries() - 1))
1741 g_restore_dbindex = 0;
1742 }
1743
1744 // Apply the inital Group Array structure to the chart database
1745 ChartData->ApplyGroupArray(g_pGroupArray);
1746}
1747
1749 wxLogMessage("opencpn::MyApp starting exit.");
1750 m_checker.OnExit();
1751 m_usb_watcher.Stop();
1752 // Send current nav status data to log file // pjotrc 2010.02.09
1753
1754 wxDateTime lognow = wxDateTime::Now();
1755 lognow.MakeGMT();
1756 wxString day = lognow.FormatISODate();
1757 wxString utc = lognow.FormatISOTime();
1758 wxString navmsg = "LOGBOOK: ";
1759 navmsg += day;
1760 navmsg += " ";
1761 navmsg += utc;
1762 navmsg += " UTC ";
1763
1764 if (bGPSValid) {
1765 wxString data;
1766 data.Printf("OFF: Lat %10.5f Lon %10.5f ", gLat, gLon);
1767 navmsg += data;
1768
1769 wxString cog;
1770 if (std::isnan(gCog))
1771 cog.Printf("COG ----- ");
1772 else
1773 cog.Printf("COG %10.5f ", gCog);
1774
1775 wxString sog;
1776 if (std::isnan(gSog))
1777 sog.Printf("SOG ----- ");
1778 else
1779 sog.Printf("SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(gSog));
1780
1781 navmsg += cog;
1782 navmsg += sog;
1783
1784 } else {
1785 wxString data;
1786 data.Printf("OFF: Lat %10.5f Lon %10.5f", gLat, gLon);
1787 navmsg += data;
1788 }
1789 wxLogMessage(navmsg);
1790 g_loglast_time = lognow;
1791
1792 if (ptcmgr) delete ptcmgr;
1793
1794 for (Track *track : g_TrackList) {
1795 delete track;
1796 }
1797 g_TrackList.clear();
1798
1799 delete pConfig;
1800 delete pSelect;
1801 delete pSelectTC;
1802 delete pSelectAIS;
1803
1804 delete ps52plib;
1805 delete g_SencThreadManager;
1806
1807 if (g_pGroupArray) {
1808 for (unsigned int igroup = 0; igroup < g_pGroupArray->GetCount();
1809 igroup++) {
1810 delete g_pGroupArray->Item(igroup);
1811 }
1812
1813 g_pGroupArray->Clear();
1814 delete g_pGroupArray;
1815 }
1816
1817 wxLogMessage("opencpn::MyApp exiting cleanly...\n");
1818 wxLog::FlushActive();
1819
1820 g_Platform->CloseLogFile();
1821
1822 delete pInit_Chart_Dir;
1823
1824 for (Track *track : g_TrackList) {
1825 delete track;
1826 }
1827 g_TrackList.clear();
1828
1829 delete g_pRouteMan;
1830 delete pWayPointMan;
1831
1832 navutil::DeinitGlobals();
1833
1834 user_colors::DeInitialize();
1835
1836 delete pLayerList;
1837
1838 delete m_pRegistrarMan;
1839 CSVDeaccess(NULL);
1840
1841 delete g_StyleManager;
1842
1843 // Restore any changed system colors
1844
1845#ifdef __WXMSW__
1846 void RestoreSystemColors();
1847 RestoreSystemColors();
1848#endif
1849
1850#ifdef __MSVC__LEAK
1851 DeInitAllocCheck();
1852#endif
1853
1854#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1856#endif
1857
1858 FontMgr::Shutdown();
1859
1860 g_Platform->OnExit_2();
1862 delete g_Platform;
1863
1864 return TRUE;
1865}
1866
1867#ifdef LINUX_CRASHRPT
1868void MyApp::OnFatalException() { g_crashprint.Report(); }
1869#endif
1870
1871//----------------------------------------------------------------------------------------------------------
1872// Application-wide CPL Error handler
1873//----------------------------------------------------------------------------------------------------------
1874void MyCPLErrorHandler(CPLErr eErrClass, int nError, const char *pszErrorMsg)
1875
1876{
1877 char msg[256];
1878
1879 if (eErrClass == CE_Debug)
1880 snprintf(msg, 255, "CPL: %s", pszErrorMsg);
1881 else if (eErrClass == CE_Warning)
1882 snprintf(msg, 255, "CPL Warning %d: %s", nError, pszErrorMsg);
1883 else
1884 snprintf(msg, 255, "CPL ERROR %d: %s", nError, pszErrorMsg);
1885
1886 wxString str(msg, wxConvUTF8);
1887 wxLogMessage(str);
1888}
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:71
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Definition chartdbs.cpp:61
arrayofCanvasPtr g_canvasArray
Global instance.
Definition chcanv.cpp:173
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:173
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
Definition chcanv.h:542
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:242
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:109
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.