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