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