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