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