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->Show();
1017 }
1018
1019 // Override for some safe and nice default values if the config file was
1020 // created from scratch
1021 if (b_initial_load) g_Platform->SetDefaultOptions();
1022
1023 g_Platform->applyExpertMode(g_bUIexpert);
1024
1025 // Now initialize UI Style.
1026 g_StyleManager = new ocpnStyle::StyleManager();
1027
1028 g_StyleManager->SetStyle("MUI_flat");
1029 if (!g_StyleManager->IsOK()) {
1030 wxString msg = _("Failed to initialize the user interface. ");
1031 msg << _("OpenCPN cannot start. ");
1032 msg << _("The necessary configuration files were not found. ");
1033 msg << _("See the log file at ") << g_Platform->GetLogFileName()
1034 << _(" for details.") << "\n\n";
1035 msg << g_Platform->GetSharedDataDir();
1036
1037 wxMessageDialog w(NULL, msg, _("Failed to initialize the user interface. "),
1038 wxCANCEL | wxICON_ERROR);
1039 w.ShowModal();
1040 exit(EXIT_FAILURE);
1041 }
1042
1043 if (g_useMUI) {
1044 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
1045 if (style) style->chartStatusWindowTransparent = true;
1046 }
1047
1048 // Init the WayPoint Manager
1049 pWayPointMan = NULL;
1050
1051 g_display_size_mm = wxMax(50, g_Platform->GetDisplaySizeMM());
1052 wxString msg;
1053 msg.Printf("Detected display size (horizontal): %d mm",
1054 (int)g_display_size_mm);
1055 wxLogMessage(msg);
1056
1057 // User override....
1058 if (g_config_display_size_manual &&
1062 wxString msg;
1063 msg.Printf("Display size (horizontal) config override: %d mm",
1064 (int)g_display_size_mm);
1065 wxLogMessage(msg);
1067 }
1068
1070
1071 if (g_btouch) {
1072 int SelectPixelRadius = 50;
1073
1074 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1075 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1076 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1077 }
1078
1079 // Is this the first run after a clean installation?
1080 if (!n_NavMessageShown) {
1081 g_bFirstRun = true;
1082 }
1083
1084 // Now we can set the locale
1085 // using wxWidgets/gettext methodology....
1086
1087#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1088
1089 // Where are the opencpn.mo files?
1090 g_Platform->SetLocaleSearchPrefixes();
1091
1092 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1093
1094 imsg = "System default Language: " + def_lang_canonical;
1095 wxLogMessage(imsg);
1096
1097 wxString cflmsg = "Config file language: " + g_locale;
1098 wxLogMessage(cflmsg);
1099
1100 if (g_locale.IsEmpty()) {
1101 g_locale = def_lang_canonical;
1102 cflmsg = "Config file language empty, using system default: " + g_locale;
1103 wxLogMessage(cflmsg);
1104 }
1105
1106 // Make any adjustments necessary
1107 g_locale = g_Platform->GetAdjustedAppLocale();
1108 cflmsg = "Adjusted App language: " + g_locale;
1109 wxLogMessage(cflmsg);
1110
1111 // Set the desired locale
1112 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1113
1114 imsg = "Opencpn language set to: ";
1115 imsg += g_locale;
1116 wxLogMessage(imsg);
1117
1118 // French language locale is assumed to include the AZERTY keyboard
1119 // This applies to either the system language, or to OpenCPN language
1120 // selection
1121 if (g_locale == "fr_FR") g_b_assume_azerty = true;
1122#else
1123 wxLogMessage("wxLocale support not available");
1124#endif
1125
1126#ifndef __ANDROID__
1127 // Now that locale is established, possibly run the startup wizard.
1128 if (g_config_wizard || b_initial_load) {
1129 FirstUseWizImpl wiz(gFrame, pConfig);
1130 auto res = wiz.Run();
1131 if (res) {
1132 g_NeedDBUpdate = 2;
1133 }
1134 }
1135#endif
1136
1137 // Instantiate and initialize the Config Manager
1138 ConfigMgr::Get();
1139
1140 // Is this an upgrade?
1141 wxString vs = wxString("Version ") + VERSION_FULL + " Build " + VERSION_DATE;
1142 g_bUpgradeInProcess = (vs != g_config_version_string);
1143
1144 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1145
1146 // log deferred log restart message, if it exists.
1147 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1148 wxLogMessage(g_Platform->GetLargeLogMessage());
1149 }
1150
1151 // Validate OpenGL functionality, if selected
1152#ifndef ocpnUSE_GL
1153 g_bdisable_opengl = true;
1154#endif
1155
1156 if (g_bdisable_opengl) g_bopengl = false;
1157
1158#if defined(__linux__) && !defined(__ANDROID__)
1159 if (g_bSoftwareGL) {
1160 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
1161 }
1162#endif
1163
1164 // FIXMW (dave) move to frame
1165 // g_bTransparentToolbarInOpenGLOK = isTransparentToolbarInOpenGLOK();
1166
1167 // On Windows platforms, establish a default cache managment policy
1168 // as allowing OpenCPN a percentage of available physical memory,
1169 // not to exceed 1 GB
1170 // Note that this logic implies that Windows platforms always use
1171 // the memCacheLimit policy, and never use the fallback nCacheLimit policy
1172#ifdef __WXMSW__
1173 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1174 g_memCacheLimit =
1175 wxMin(g_memCacheLimit, 1024 * 1024); // math in kBytes, Max is 1 GB
1176#else
1177 // All other platforms will use the nCacheLimit policy
1178 // sinc on linux it is impossible to accurately measure the application memory
1179 // footprint without expensive methods such as malloc/free tracking, and such
1180
1181 g_memCacheLimit = 0;
1182 if (0 == g_nCacheLimit) // allow config file override
1183 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1184#endif
1185
1186 // Establish location and name of chart database
1187 ChartListFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(),
1188 "chartlist.dat", "CHRTLIST.DAT");
1189
1190 // Establish location and name of AIS MMSI -> Target Name mapping
1191 AISTargetNameFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(),
1192 "mmsitoname.csv", "MMSINAME.CSV");
1193
1194 // Establish guessed location of chart tree
1195 if (pInit_Chart_Dir->IsEmpty()) {
1196 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1197
1198 if (!g_bportable)
1199#ifndef __ANDROID__
1200 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1201#else
1202 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1203#endif
1204 }
1205
1206 InitRestListeners();
1207
1208 // Establish the GSHHS Dataset location
1209 gDefaultWorldMapLocation = "gshhs";
1210 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1211 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1212 if (gWorldMapLocation == wxEmptyString) {
1213 gWorldMapLocation = gDefaultWorldMapLocation;
1214 }
1215
1216 // Check the global Tide/Current data source array
1217 // If empty, preset default (US + ROW) data sources
1218 wxString default_tcdata0 =
1219 (g_Platform->GetSharedDataDir() + "tcdata" +
1220 wxFileName::GetPathSeparator() + "harmonics-dwf-20210110-free.tcd");
1221 wxString default_tcdata1 =
1222 (g_Platform->GetSharedDataDir() + "tcdata" +
1223 wxFileName::GetPathSeparator() + "HARMONICS_NO_US.IDX");
1224 wxString default_tcdata2 =
1225 (g_Platform->GetSharedDataDir() + "tcdata" +
1226 wxFileName::GetPathSeparator() + "ticon-europe-global.tcd");
1227
1228 if (TideCurrentDataSet.empty()) {
1229 TideCurrentDataSet.push_back(
1230 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1231 TideCurrentDataSet.push_back(
1232 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1233 TideCurrentDataSet.push_back(
1234 g_Platform->NormalizePath(default_tcdata2).ToStdString());
1235 }
1236
1237 // Check the global AIS alarm sound file
1238 // If empty, preset default
1239 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1240 wxString default_sound = (g_Platform->GetSharedDataDir() + "sounds" +
1241 wxFileName::GetPathSeparator() + "2bells.wav");
1242 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1243 }
1244
1245 gpIDXn = 0;
1246
1247 g_Platform->Initialize_2();
1248
1249 LoadChartDatabase();
1250
1251 // Kiosk startup mode only available in linux/GTK builds.
1252#ifndef __WXGTK__
1253 g_kiosk_startup = false;
1254#endif
1255
1256 // Create and initialize the main application frame.
1257 if (!g_kiosk_startup) {
1258 BuildMainFrame();
1259 SetTopWindow(gFrame); // Set the main frame as the new top window.
1260 gFrame->Show();
1261 gFrame->Raise();
1262 } else {
1263 wxTheApp->CallAfter(&MyApp::OnWallpaperStable);
1264 }
1265
1266 OCPNPlatform::Initialize_4();
1267
1268#ifdef __ANDROID__
1269 androidHideBusyIcon();
1270#endif
1271 wxLogMessage(
1272 wxString::Format(_("OpenCPN Initialized in %ld ms."), init_sw.Time()));
1273
1274 wxMilliSleep(100);
1275
1276 if (!g_kiosk_startup) {
1277 if (!DoNavMessage(vs)) {
1278 Exit();
1279 }
1280 }
1281
1282 // As an a.e. Raspberry does not have a hardwareclock we will have some
1283 // problems with date/time setting
1284 g_bHasHwClock = true; // by default most computers do have a hwClock
1285#if defined(__UNIX__) && !defined(__ANDROID__)
1286 struct stat buffer;
1287 g_bHasHwClock =
1288 ((stat("/dev/rtc", &buffer) == 0) || (stat("/dev/rtc0", &buffer) == 0) ||
1289 (stat("/dev/misc/rtc", &buffer) == 0));
1290#endif
1291
1292 g_config_version_string = vs;
1293
1294 // The user accepted the "not for navigation" nag, so persist it here...
1295 pConfig->UpdateSettings();
1296
1297 for (auto *cp : TheConnectionParams()) {
1298 if (cp->bEnabled) {
1299 if (cp->GetDSPort().Contains("Serial")) {
1300 std::string port(cp->Port.ToStdString());
1302 }
1303 }
1304 }
1306
1307 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1308
1309 // If network connection is available, start the server and mDNS client
1310 if (ipv4_addrs.size()) {
1311 std::string ipAddr = ipv4_addrs[0];
1312
1313 wxString data_dir = g_Platform->GetPrivateDataDir();
1314 if (data_dir.Last() != wxFileName::GetPathSeparator())
1315 data_dir.Append(wxFileName::GetPathSeparator());
1316
1317 make_certificate(ipAddr, data_dir.ToStdString());
1318
1319 m_rest_server.StartServer(fs::path(data_dir.ToStdString()));
1320 StartMDNSService(g_hostname.ToStdString(), "opencpn-object-control-service",
1321 8000);
1322 }
1323
1324 if (!g_kiosk_startup) {
1325 // Ensure execution after all pending layout events
1326 CallAfter([]() {
1327 // Start delayed initialization chain after some milliseconds
1328 wxLogMessage("InitTimer start");
1329 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1330 });
1331 }
1332
1333 return TRUE;
1334}
1335
1337 BuildMainFrame();
1338 // Ensure execution after all pending layout events
1339 CallAfter([this]() {
1340 // Hide the old frame and show the new one.
1341 g_wallpaper->Show(false);
1343 g_bFullscreen = true;
1344
1345 // Cleanup the wallpaper frame.
1346 g_wallpaper->Destroy();
1347 g_wallpaper = nullptr;
1348
1349 SetTopWindow(gFrame); // Set the main frame as the new top window.
1350 gFrame->Raise();
1351
1352 wxString vs =
1353 wxString("Version ") + VERSION_FULL + " Build " + VERSION_DATE;
1354 if (!DoNavMessage(vs)) {
1355 Exit();
1356 }
1357
1358 CallAfter([]() { // nested...
1359 // Start delayed initialization chain after some milliseconds
1360 wxLogMessage("InitTimer start");
1361 gFrame->InitTimer.Start(10, wxTIMER_CONTINUOUS);
1362 });
1363 });
1364}
1365
1366void MyApp::BuildMainFrame() {
1367 // Set up the frame initial visual parameters
1368 // Default size, resized later
1369 wxSize new_frame_size(-1, -1);
1370 int cx, cy, cw, ch;
1371 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1372
1373 user_colors::Initialize();
1374
1375 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1376 (g_nframewin_y <= ch))
1377 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1378 else
1379 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1380
1381 // Try to detect any change in physical screen configuration
1382 // This can happen when drivers are changed, for instance....
1383 // and can confuse the WUI layout perspective stored in the config file.
1384 // If detected, force a nominal window size and position....
1385 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1386 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1387 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1388 g_bframemax = false;
1389 }
1390
1391 g_lastClientRectx = cx;
1392 g_lastClientRecty = cy;
1393 g_lastClientRectw = cw;
1394 g_lastClientRecth = ch;
1395
1396 // Validate config file position
1397 wxPoint position(0, 0);
1398 wxSize dsize = wxGetDisplaySize();
1399
1400#ifdef __WXMAC__
1401 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1402#endif
1403
1404 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1405 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1406
1407#ifdef __WXMSW__
1408 // Support MultiMonitor setups which can allow negative window positions.
1409 RECT frame_rect;
1410 frame_rect.left = position.x;
1411 frame_rect.top = position.y;
1412 frame_rect.right = position.x + new_frame_size.x;
1413 frame_rect.bottom = position.y + new_frame_size.y;
1414
1415 // If the requested frame window does not intersect any installed monitor,
1416 // then default to simple primary monitor positioning.
1417 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1418 position = wxPoint(10, 10);
1419#endif
1420
1421#ifdef __WXOSX__
1422 // Support MultiMonitor setups which can allow negative window positions.
1423 const wxPoint ptScreen(position.x, position.y);
1424 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1425
1426 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1427#endif
1428
1429 g_nframewin_posx = position.x;
1430 g_nframewin_posy = position.y;
1431
1432#ifdef __ANDROID__
1433 wxSize asz = getAndroidDisplayDimensions();
1434 ch = asz.y;
1435 cw = asz.x;
1436 // qDebug() << cw << ch;
1437
1438 if ((cw > 200) && (ch > 200))
1439 new_frame_size.Set(cw, ch);
1440 else
1441 new_frame_size.Set(800, 400);
1442#endif
1443
1444 // Create the main frame window
1445
1446 // Strip the commit SHA number from the string to be shown in frame title.
1447 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst('+');
1448 wxString myframe_window_title = wxString("OpenCPN " + short_version_name);
1449
1450 if (g_bportable) {
1451 myframe_window_title += _(" -- [Portable(-p) executing from ");
1452 myframe_window_title += g_Platform->GetHomeDir();
1453 myframe_window_title += "]";
1454 }
1455
1456 wxString fmsg;
1457 fmsg.Printf("Creating MyFrame...size(%d, %d) position(%d, %d)",
1458 new_frame_size.x, new_frame_size.y, position.x, position.y);
1459 wxLogMessage(fmsg);
1460
1462 auto dockart = new wxAuiDefaultDockArt;
1463 g_pauimgr->SetArtProvider(dockart);
1464
1465 gFrame = new MyFrame(myframe_window_title, position, new_frame_size,
1466 m_rest_server, dockart,
1467 [&](const std::string &path) { return OpenFile(path); });
1468
1469 // Initialize the Plugin Manager
1470 g_pi_manager = new PlugInManager(gFrame);
1471
1472 g_pauimgr->SetDockSizeConstraint(.9, .9);
1473
1474 // tell wxAuiManager to manage the frame
1475 g_pauimgr->SetManagedWindow(gFrame);
1476
1477 // Do those platform specific initialization things that need gFrame
1478 g_Platform->Initialize_3();
1479
1480 gFrame->CreateCanvasLayout();
1481
1482 gFrame->SetGPSCompassScale();
1483
1484 // gFrame->RequestNewMasterToolbar( true );
1485
1486 gFrame->SetChartUpdatePeriod(); // Reasonable default
1487
1488 pthumbwin = new ThumbWin(gFrame->GetPrimaryCanvas());
1489
1490 gFrame->ApplyGlobalSettings(false); // done once on init with resize
1491 gFrame->SetAllToolbarScale();
1492 gFrame->SetAndApplyColorScheme(global_color_scheme);
1493 if (g_bframemax) gFrame->Maximize(true);
1494
1495#ifdef __ANDROID__
1496 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->GetPixPerMM() > 4.0))
1497 gFrame->Maximize(true);
1498#endif
1499
1500 // All set to go.....
1501
1502 // Process command line option to rebuild cache
1503#ifdef ocpnUSE_GL
1504 extern ocpnGLOptions g_GLOptions;
1505
1506 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1507 g_GLOptions.m_bTextureCompressionCaching) {
1508 gFrame->ReloadAllVP(); // Get a nice chart background loaded
1509
1510 // Turn off the toolbar as a clear signal that the system is busy right
1511 // now.
1512 // Note: I commented this out because the toolbar never comes back for me
1513 // and is unusable until I restart opencpn without generating the cache
1514 // if( g_MainToolbar )
1515 // g_MainToolbar->Hide();
1516
1517 if (g_glTextureManager) g_glTextureManager->BuildCompressedCache();
1518 }
1519#endif
1520
1521 // FIXME (dave)
1522 // move method to frame
1523 // if (g_parse_all_enc) ParseAllENC(gFrame);
1524
1525 // establish GPS timeout value as multiple of frame timer
1526 // This will override any nonsense or unset value from the config file
1527 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1528 gps_watchdog_timeout_ticks = (kGpsTimeoutSeconds * 1000) / TIMER_GFRAME_1;
1529
1530 wxString dogmsg;
1531 dogmsg.Printf("GPS Watchdog Timeout is: %d sec.", gps_watchdog_timeout_ticks);
1532 wxLogMessage(dogmsg);
1533
1534 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1535
1536 g_priSats = 99;
1537
1538 // Most likely installations have no ownship heading information
1539 g_bVAR_Rx = false;
1540
1541 // Start up a new track if enabled in config file
1542 if (g_bTrackCarryOver) g_bDeferredStartTrack = true;
1543
1544 pAnchorWatchPoint1 = NULL;
1545 pAnchorWatchPoint2 = NULL;
1546
1547 gFrame->DoChartUpdate();
1548
1549 CommBridge::GetInstance();
1550
1551 // Load comm connections
1552 for (auto *cp : TheConnectionParams()) {
1553 if (cp->bEnabled) {
1554 MakeCommDriver(cp);
1555 cp->b_IsSetup = TRUE;
1556 }
1557 }
1559
1560 // Load and initialize plugins
1561 auto style = g_StyleManager->GetCurrentStyle();
1562 auto bitmap = new wxBitmap(style->GetIcon("default_pi", 32, 32));
1563 if (bitmap->IsOk())
1564 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1565 else
1566 wxLogWarning("Cannot initiate plugin default jigsaw icon.");
1567
1568 AbstractPlatform::ShowBusySpinner();
1569 PluginLoader::GetInstance()->LoadAllPlugIns(true);
1570 AbstractPlatform::HideBusySpinner();
1571
1572 if (g_kiosk_startup) g_pi_manager->CallLateInit();
1573
1574 wxString perspective;
1575 pConfig->SetPath("/AUI");
1576 pConfig->Read("AUIPerspective", &perspective);
1577
1578 // Make sure the perspective saved in the config file is "reasonable"
1579 // In particular, the perspective should have an entry for every
1580 // windows added to the AUI manager so far.
1581 // If any are not found, then use the default layout
1582
1583 bool bno_load = false;
1584
1585 wxArrayString name_array;
1586 wxStringTokenizer st(perspective, "|;");
1587 while (st.HasMoreTokens()) {
1588 wxString s1 = st.GetNextToken();
1589 if (s1.StartsWith("name=")) {
1590 wxString sc = s1.AfterFirst('=');
1591 name_array.Add(sc);
1592 }
1593 }
1594
1595 wxAuiPaneInfoArray pane_array_val = g_pauimgr->GetAllPanes();
1596 for (unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
1597 wxAuiPaneInfo pane = pane_array_val.Item(i);
1598
1599 // If we find a pane that is not in the perspective,
1600 // then we should not load the perspective at all
1601 if (name_array.Index(pane.name) == wxNOT_FOUND) {
1602 bno_load = true;
1603 break;
1604 }
1605 }
1606
1607 if (!bno_load) g_pauimgr->LoadPerspective(perspective, false);
1608
1609 // Touch up the AUI manager
1610 // Make sure that any pane width is reasonable default value
1611#if 0 // TODO nees this?
1612 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1613 ChartCanvas *cc = g_canvasArray.Item(i);
1614 if (cc) {
1615 wxSize frameSize = GetClientSize();
1616 wxSize minSize = g_pauimgr->GetPane(cc).min_size;
1617 int width = wxMax(minSize.x, frameSize.x / 10);
1618 g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
1619 }
1620 }
1621 g_pauimgr->Update();
1622#endif
1623 g_pauimgr->Update();
1624
1625 // Notify all the AUI PlugIns so that they may syncronize with the
1626 // Perspective
1627 g_pi_manager->NotifyAuiPlugIns();
1628
1629 // Give the user dialog on any blacklisted PlugIns
1630 g_pi_manager->ShowDeferredBlacklistMessages();
1631 // g_pi_manager->CallLateInit();
1632
1633 return;
1634
1635 // This little hack fixes a problem seen with some UniChrome OpenGL drivers
1636 // We need a deferred resize to get glDrawPixels() to work right.
1637 // So we set a trigger to generate a resize after 5 seconds....
1638 // See the "UniChrome" hack elsewhere
1639#ifdef ocpnUSE_GL
1640 if (!g_bdisable_opengl) {
1641 glChartCanvas *pgl =
1642 (glChartCanvas *)gFrame->GetPrimaryCanvas()->GetglCanvas();
1643 if (pgl && (pgl->GetRendererString().Find("UniChrome") != wxNOT_FOUND)) {
1644 gFrame->m_defer_size = gFrame->GetSize();
1645 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1646 g_pauimgr->Update();
1647 gFrame->m_bdefer_resize = true;
1648 }
1649 }
1650#endif
1651
1652 // Horrible Hack (tm): Make sure the RoutePoint destructor can invoke
1653 // glDeleteTextures. Truly awful.
1654#ifdef ocpnUSE_GL
1655 if (g_bopengl)
1656 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {
1657 glDeleteTextures(n, texts);
1658 };
1659#else
1660 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {};
1661#endif
1662
1663#ifdef __ANDROID__
1664 // We need a resize to pick up height adjustment after building android
1665 // ActionBar
1666 gFrame->SetSize(getAndroidDisplayDimensions());
1667 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1668#endif
1669
1670 // Setup Tides/Currents to settings present at last shutdown
1671 // TODO
1672 // gFrame->ShowTides( g_bShowTide );
1673 // gFrame->ShowCurrents( g_bShowCurrent );
1674
1675 // wxLogMessage( wxString::Format("OpenCPN Initialized in %ld ms.",
1676 // init_sw.Time() ) );
1677}
1678
1679void MyApp::LoadChartDatabase() {
1680 // Build the initial chart dir array
1681 ArrayOfCDI ChartDirArray;
1682 pConfig->LoadChartDirArray(ChartDirArray);
1683
1684 // Windows installer may have left hints regarding the initial chart dir
1685 // selection
1686#ifdef __WXMSW__
1687 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1688 int ndirs = 0;
1689
1690 wxRegKey RegKey(wxString("HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN"));
1691 if (RegKey.Exists()) {
1692 wxLogMessage(
1693 _("Retrieving initial Chart Directory set from Windows Registry"));
1694 wxString dirs;
1695 RegKey.QueryValue(wxString("ChartDirs"), dirs);
1696
1697 wxStringTokenizer tkz(dirs, ";");
1698 while (tkz.HasMoreTokens()) {
1699 wxString token = tkz.GetNextToken();
1700
1701 ChartDirInfo cdi;
1702 cdi.fullpath = token.Trim();
1703 cdi.magic_number = "";
1704
1705 ChartDirArray.Add(cdi);
1706 ndirs++;
1707 }
1708 }
1709
1710 if (g_bportable) {
1711 ChartDirInfo cdi;
1712 cdi.fullpath = "charts";
1713 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1714 cdi.magic_number = "";
1715 ChartDirArray.Add(cdi);
1716 ndirs++;
1717 }
1718
1719 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1720 }
1721#endif
1722
1723 // If the ChartDirArray is empty at this point, any existing chart database
1724 // file must be declared invalid, So it is best to simply delete it if
1725 // present.
1726 // TODO There is a possibility of recreating the dir list from the
1727 // database itself......
1728
1729 if (!ChartDirArray.GetCount())
1730 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1731
1732 // Try to load the current chart list Data file
1733 ChartData = new ChartDB();
1734 if (g_NeedDBUpdate == 0 && ChartDirArray.GetCount() &&
1735 !ChartData->LoadBinary(ChartListFileName, ChartDirArray)) {
1736 g_NeedDBUpdate = 1;
1737 g_restore_dbindex = 0;
1738 }
1739
1740 // Verify any saved chart database startup index
1741 if (g_restore_dbindex >= 0) {
1742 if (ChartData->GetChartTableEntries() == 0)
1743 g_restore_dbindex = -1;
1744
1745 else if (g_restore_dbindex > (ChartData->GetChartTableEntries() - 1))
1746 g_restore_dbindex = 0;
1747 }
1748
1749 // Apply the inital Group Array structure to the chart database
1750 ChartData->ApplyGroupArray(g_pGroupArray);
1751}
1752
1754 wxLogMessage("opencpn::MyApp starting exit.");
1755 m_checker.OnExit();
1756 m_usb_watcher.Stop();
1757 // Send current nav status data to log file // pjotrc 2010.02.09
1758
1759 wxDateTime lognow = wxDateTime::Now();
1760 lognow.MakeGMT();
1761 wxString day = lognow.FormatISODate();
1762 wxString utc = lognow.FormatISOTime();
1763 wxString navmsg = "LOGBOOK: ";
1764 navmsg += day;
1765 navmsg += " ";
1766 navmsg += utc;
1767 navmsg += " UTC ";
1768
1769 if (bGPSValid) {
1770 wxString data;
1771 data.Printf("OFF: Lat %10.5f Lon %10.5f ", gLat, gLon);
1772 navmsg += data;
1773
1774 wxString cog;
1775 if (std::isnan(gCog))
1776 cog.Printf("COG ----- ");
1777 else
1778 cog.Printf("COG %10.5f ", gCog);
1779
1780 wxString sog;
1781 if (std::isnan(gSog))
1782 sog.Printf("SOG ----- ");
1783 else
1784 sog.Printf("SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(gSog));
1785
1786 navmsg += cog;
1787 navmsg += sog;
1788
1789 } else {
1790 wxString data;
1791 data.Printf("OFF: Lat %10.5f Lon %10.5f", gLat, gLon);
1792 navmsg += data;
1793 }
1794 wxLogMessage(navmsg);
1795 g_loglast_time = lognow;
1796
1797 if (ptcmgr) delete ptcmgr;
1798
1799 for (Track *track : g_TrackList) {
1800 delete track;
1801 }
1802 g_TrackList.clear();
1803
1804 delete pConfig;
1805 delete pSelect;
1806 delete pSelectTC;
1807 delete pSelectAIS;
1808
1809 delete ps52plib;
1810 delete g_SencThreadManager;
1811
1812 if (g_pGroupArray) {
1813 for (unsigned int igroup = 0; igroup < g_pGroupArray->GetCount();
1814 igroup++) {
1815 delete g_pGroupArray->Item(igroup);
1816 }
1817
1818 g_pGroupArray->Clear();
1819 delete g_pGroupArray;
1820 }
1821
1822 wxLogMessage("opencpn::MyApp exiting cleanly...\n");
1823 wxLog::FlushActive();
1824
1825 g_Platform->CloseLogFile();
1826
1827 delete pInit_Chart_Dir;
1828
1829 for (Track *track : g_TrackList) {
1830 delete track;
1831 }
1832 g_TrackList.clear();
1833
1834 delete g_pRouteMan;
1835 delete pWayPointMan;
1836
1837 navutil::DeinitGlobals();
1838
1839 user_colors::DeInitialize();
1840
1841 delete pLayerList;
1842
1843 delete m_pRegistrarMan;
1844 CSVDeaccess(NULL);
1845
1846 delete g_StyleManager;
1847
1848 // Restore any changed system colors
1849
1850#ifdef __WXMSW__
1851 void RestoreSystemColors();
1852 RestoreSystemColors();
1853#endif
1854
1855#ifdef __MSVC__LEAK
1856 DeInitAllocCheck();
1857#endif
1858
1859#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1861#endif
1862
1863 FontMgr::Shutdown();
1864
1865 g_Platform->OnExit_2();
1867 delete g_Platform;
1868
1869 return TRUE;
1870}
1871
1872#ifdef LINUX_CRASHRPT
1873void MyApp::OnFatalException() { g_crashprint.Report(); }
1874#endif
1875
1876//----------------------------------------------------------------------------------------------------------
1877// Application-wide CPL Error handler
1878//----------------------------------------------------------------------------------------------------------
1879void MyCPLErrorHandler(CPLErr eErrClass, int nError, const char *pszErrorMsg)
1880
1881{
1882 char msg[256];
1883
1884 if (eErrClass == CE_Debug)
1885 snprintf(msg, 255, "CPL: %s", pszErrorMsg);
1886 else if (eErrClass == CE_Warning)
1887 snprintf(msg, 255, "CPL Warning %d: %s", nError, pszErrorMsg);
1888 else
1889 snprintf(msg, 255, "CPL ERROR %d: %s", nError, pszErrorMsg);
1890
1891 wxString str(msg, wxConvUTF8);
1892 wxLogMessage(str);
1893}
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:108
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.