OpenCPN Partial API docs
Loading...
Searching...
No Matches
ocpn_app.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: OpenCPN Main wxWidgets Program
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 **************************************************************************/
25#include "config.h"
26
27#ifdef __MINGW32__
28#undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
29#include <windows.h>
30#endif
31
32#include <wx/wxprec.h>
33
34#ifndef WX_PRECOMP
35#include <wx/wx.h>
36#endif // precompiled headers
37#ifdef __WXMSW__
38// #include "c:\\Program Files\\visual leak detector\\include\\vld.h"
39#endif
40
41#include <algorithm>
42#include <limits.h>
43#include <memory>
44#include <thread>
45
46#ifdef __WXMSW__
47#include <math.h>
48#include <psapi.h>
49#include <stdlib.h>
50#include <time.h>
51#endif
52
53#ifndef __WXMSW__
54#include <setjmp.h>
55#include <signal.h>
56#endif
57
58#ifdef OCPN_HAVE_X11
59#include <X11/Xatom.h>
60#include <X11/Xlib.h>
61#endif
62
63#if (defined(OCPN_GHC_FILESYSTEM) || \
64 (defined(__clang_major__) && (__clang_major__ < 15)))
65// MacOS 1.13
66#include <ghc/filesystem.hpp>
67namespace fs = ghc::filesystem;
68#else
69#include <filesystem>
70#include <utility>
71namespace fs = std::filesystem;
72#endif
73
74using namespace std::literals::chrono_literals;
75
76#include <wx/apptrait.h>
77#include <wx/arrimpl.cpp>
78#include <wx/artprov.h>
79#include <wx/aui/aui.h>
80#include <wx/clrpicker.h>
81#include <wx/cmdline.h>
82#include <wx/dialog.h>
83#include <wx/dialog.h>
84#include <wx/dir.h>
85#include <wx/display.h>
86#include <wx/dynlib.h>
87#include <wx/image.h>
88#include <wx/intl.h>
89#include <wx/ipc.h>
90#include <wx/jsonreader.h>
91#include <wx/listctrl.h>
92#include <wx/power.h>
93#include <wx/printdlg.h>
94#include <wx/print.h>
95#include <wx/progdlg.h>
96#include <wx/settings.h>
97#include <wx/stdpaths.h>
98#include <wx/tokenzr.h>
99
100#include "model/ais_decoder.h"
101#include "model/ais_state_vars.h"
102#include "model/certificates.h"
103#include "model/cmdline.h"
104#include "model/comm_bridge.h"
105#include "model/comm_n0183_output.h"
106#include "model/comm_vars.h"
107#include "model/config_vars.h"
108#include "model/instance_check.h"
109#include "model/local_api.h"
110#include "model/logger.h"
111#include "model/mdns_query.h"
112#include "model/mdns_service.h"
113#include "model/multiplexer.h"
114#include "model/nav_object_database.h"
115#include "model/navutil_base.h"
117#include "model/own_ship.h"
118#include "model/plugin_handler.h"
119#include "model/route.h"
120#include "model/routeman.h"
121#include "model/select.h"
122#include "model/track.h"
123
124#include "about_frame_impl.h"
125#include "about.h"
126#include "ais_info_gui.h"
127#include "AISTargetAlertDialog.h"
128#include "AISTargetListDialog.h"
129#include "AISTargetQueryDialog.h"
130#include "CanvasConfig.h"
131#include "chartdb.h"
132#include "chcanv.h"
133#include "cm93.h"
134#include "concanv.h"
135#include "config.h"
136#include "ConfigMgr.h"
137#include "DetailSlider.h"
138#include "dychart.h"
139#include "FontMgr.h"
140#include "gdal/cpl_csv.h"
141#include "glTexCache.h"
142#include "GoToPositionDialog.h"
143#include "Layer.h"
144#include "MarkInfo.h"
145#include "navutil.h"
146#include "observable.h"
147#include "ocpn_app.h"
148#include "OCPN_AUIManager.h"
149#include "ocpn_frame.h"
150#include "OCPNPlatform.h"
151#include "options.h"
152#include "rest_server_gui.h"
153#include "route_ctx_factory.h"
154#include "routemanagerdialog.h"
155#include "routeman_gui.h"
156#include "RoutePropDlgImpl.h"
157#include "s52plib.h"
158#include "s57chart.h"
159#include "S57QueryDialog.h"
160#include "safe_mode_gui.h"
161#include "SoundFactory.h"
162#include "styles.h"
163#include "tcmgr.h"
164#include "thumbwin.h"
165#include "TrackPropDlg.h"
166#include "udev_rule_mgr.h"
167
168#ifdef ocpnUSE_GL
169#include "glChartCanvas.h"
170#endif
171
172#ifdef __WXOSX__
173#include "model/macutils.h"
174#endif
175
176#ifdef __WXMSW__
177#include "model/garmin_protocol_mgr.h" // Used for port probing on Windows
178void RedirectIOToConsole();
179#endif
180
181#if defined(__WXMSW__) && defined(__MSVC__LEAK)
182#include "Stackwalker.h"
183#endif
184
185#ifdef LINUX_CRASHRPT
186#include "crashprint.h"
187#endif
188
189#ifdef __ANDROID__
190#include "androidUTIL.h"
191#else
192#include "serial/serial.h"
193#endif
194#include "wiz_ui.h"
195
196const char *const kUsage =
197 R"(Usage:
198 opencpn -h | --help
199 opencpn [-p] [-f] [-G] [-g] [-P] [-l <str>] [-u <num>] [-U] [-s] [GPX file ...]
200 opencpn --remote [-R] | -q] | -e] |-o <str>]
201
202Options for starting opencpn
203
204 -c, --configdir=<dirpath> Use alternative configuration directory.
205 -p, --portable Run in portable mode.
206 -f, --fullscreen Switch to full screen mode on start.
207 -G, --no_opengl Disable OpenGL video acceleration. This setting will
208 be remembered.
209 -g, --rebuild_gl_raster_cache Rebuild OpenGL raster cache on start.
210 -D, --rebuild_chart_db Rescan chart directories and rebuild the chart database
211 -P, --parse_all_enc Convert all S-57 charts to OpenCPN's internal format on start.
212 -l, --loglevel=<str> Amount of logging: error, warning, message, info, debug or trace
213 -u, --unit_test_1=<num> Display a slideshow of <num> charts and then exit.
214 Zero or negative <num> specifies no limit.
215 -U, --unit_test_2
216 -s, --safe_mode Run without plugins, opengl and other "dangerous" stuff
217 -W, --config_wizard Start with initial configuration wizard
218
219Options manipulating already started opencpn
220 -r, --remote Execute commands on already running instance
221 -R, --raise Make running OpenCPN visible if hidden
222 -q, --quit Terminate already running opencpn
223 -e, --get_rest_endpoint Print rest server endpoint and exit.
224 -o, --open=<GPX file> Open file in running opencpn
225
226Arguments:
227 GPX file GPX-formatted file with waypoints or routes.
228)";
229
230// comm event definitions
231wxDEFINE_EVENT(EVT_N2K_129029, wxCommandEvent);
232wxDEFINE_EVENT(EVT_N2K_129026, wxCommandEvent);
233
234wxDEFINE_EVENT(EVT_N0183_RMC, wxCommandEvent);
235wxDEFINE_EVENT(EVT_N0183_HDT, wxCommandEvent);
236wxDEFINE_EVENT(EVT_N0183_HDG, wxCommandEvent);
237wxDEFINE_EVENT(EVT_N0183_HDM, wxCommandEvent);
238wxDEFINE_EVENT(EVT_N0183_VTG, wxCommandEvent);
239wxDEFINE_EVENT(EVT_N0183_GSV, wxCommandEvent);
240wxDEFINE_EVENT(EVT_N0183_GGA, wxCommandEvent);
241wxDEFINE_EVENT(EVT_N0183_GLL, wxCommandEvent);
242wxDEFINE_EVENT(EVT_N0183_AIVDO, wxCommandEvent);
243
244//------------------------------------------------------------------------------
245// Fwd Declarations
246//------------------------------------------------------------------------------
247
248//------------------------------------------------------------------------------
249// Static variable definition
250//------------------------------------------------------------------------------
251
252WX_DEFINE_OBJARRAY(ArrayOfCDI);
253
254OCPNPlatform *g_Platform;
255
256bool g_bFirstRun;
257bool g_bUpgradeInProcess;
258
259bool g_bPauseTest;
260
261// Files specified on the command line, if any.
262
263MyFrame *gFrame;
264
265ConsoleCanvas *console;
266
267MyConfig *pConfig;
268ChartDB *ChartData;
269int g_restore_stackindex;
270int g_restore_dbindex;
271double g_ChartNotRenderScaleFactor;
272
273LayerList *pLayerList;
274
275Select *pSelectTC;
276
277MarkInfoDlg *g_pMarkInfoDialog;
278RoutePropDlgImpl *pRoutePropDialog;
279TrackPropDlg *pTrackPropDialog;
280RouteManagerDialog *pRouteManagerDialog;
281GoToPositionDialog *pGoToPositionDialog;
282
283double vLat, vLon;
284
285int g_nbrightness = 100;
286
287bool bDBUpdateInProgress;
288
289ThumbWin *pthumbwin;
290TCMgr *ptcmgr;
291
292bool g_bshowToolbar = true;
293bool g_bexpert = true;
294bool g_bBasicMenus = false;
295
296bool bDrawCurrentValues;
297
298wxString ChartListFileName;
299wxString gWorldMapLocation, gDefaultWorldMapLocation;
300wxString gWorldShapefileLocation;
301wxString *pInit_Chart_Dir;
302wxString g_csv_locn;
303wxString g_SENCPrefix;
304wxString g_UserPresLibData;
305wxString g_VisibleLayers;
306wxString g_InvisibleLayers;
307wxString g_VisiNameinLayers;
308wxString g_InVisiNameinLayers;
309
310bool g_bcompression_wait;
311bool g_FlushNavobjChanges;
312int g_FlushNavobjChangesTimeout;
313
314wxString g_uploadConnection;
315
316int user_user_id;
317int file_user_id;
318
319int quitflag;
320int g_tick = 0;
321int g_mem_total, g_mem_initial;
322
323bool s_bSetSystemTime;
324
325static unsigned int malloc_max;
326
327wxDateTime g_start_time;
328wxDateTime g_loglast_time;
329static OcpnSound *_bells_sounds[] = {SoundFactory(), SoundFactory()};
330std::vector<OcpnSound *> bells_sound(_bells_sounds, _bells_sounds + 2);
331
332OcpnSound *g_anchorwatch_sound = SoundFactory();
333
334double AnchorPointMinDist;
335bool AnchorAlertOn1, AnchorAlertOn2;
336bool g_bCruising;
337
338ChartDummy *pDummyChart;
339
340ocpnStyle::StyleManager *g_StyleManager;
341
342bool g_bShowOutlines;
343bool g_bShowDepthUnits;
344bool g_bDisplayGrid; // Flag indicating weather the lat/lon grid should be
345 // displayed
346bool g_bShowChartBar;
347bool g_bShowActiveRouteHighway;
348int g_nAWDefault;
349int g_nAWMax;
350bool g_bPlayShipsBells;
351bool g_bFullscreenToolbar;
352bool g_bShowLayers;
353bool g_bTransparentToolbar;
354bool g_bTransparentToolbarInOpenGLOK;
355int g_nAutoHideToolbar;
356bool g_bAutoHideToolbar;
357
358bool g_bPermanentMOBIcon;
359bool g_bTempShowMenuBar;
360
361int g_iNavAidRadarRingsNumberVisible;
362bool g_bNavAidRadarRingsShown;
363float g_fNavAidRadarRingsStep;
364int g_pNavAidRadarRingsStepUnits;
365bool g_bWayPointPreventDragging;
366bool g_bConfirmObjectDelete;
367wxColour g_colourOwnshipRangeRingsColour;
368int g_maxzoomin;
369
370// Set default color scheme
371ColorScheme global_color_scheme = GLOBAL_COLOR_SCHEME_DAY;
372
373wxArrayPtrVoid *UserColourHashTableArray;
374wxColorHashMap *pcurrent_user_color_hash;
375
376bool bVelocityValid;
377
378int gHDx_Watchdog;
379
380bool g_bDebugCM93;
381bool g_bDebugS57;
382
383int g_ChartUpdatePeriod;
384int g_SkewCompUpdatePeriod;
385
386int g_lastClientRectx;
387int g_lastClientRecty;
388int g_lastClientRectw;
389int g_lastClientRecth;
393double g_display_size_mm;
394std::vector<size_t> g_config_display_size_mm;
395bool g_config_display_size_manual;
396
397int g_GUIScaleFactor;
398int g_ChartScaleFactor;
399float g_MarkScaleFactorExp;
400int g_last_ChartScaleFactor;
401int g_ShipScaleFactor;
402float g_ShipScaleFactorExp;
403int g_ENCSoundingScaleFactor;
404int g_ENCTextScaleFactor;
405
406bool g_bShowTide;
407bool g_bShowCurrent;
408
409s52plib *ps52plib;
410s57RegistrarMgr *m_pRegistrarMan;
411
412CM93OffsetDialog *g_pCM93OffsetDialog;
413
414#ifdef __WXOSX__
415#include "model/macutils.h"
416#endif
417
418// begin rms
419#ifdef __WXOSX__
420#ifdef __WXMSW__
421#ifdef USE_GLU_TESS
422#ifdef USE_GLU_DLL
423// end rms
424extern bool s_glu_dll_ready;
425extern HINSTANCE s_hGLU_DLL; // Handle to DLL
426#endif
427#endif
428#endif
429#endif
430
431double g_ownship_predictor_minutes;
432double g_ownship_HDTpredictor_miles;
433int g_cog_predictor_style;
434wxString g_cog_predictor_color;
435int g_cog_predictor_endmarker;
436int g_ownship_HDTpredictor_style;
437wxString g_ownship_HDTpredictor_color;
438int g_ownship_HDTpredictor_endmarker;
439int g_ownship_HDTpredictor_width;
440
441bool g_own_ship_sog_cog_calc;
442int g_own_ship_sog_cog_calc_damp_sec;
443
444AisInfoGui *g_pAISGUI;
445
446AISTargetQueryDialog *g_pais_query_dialog_active;
447int g_iSoundDeviceIndex;
448
449int g_S57_dialog_sx, g_S57_dialog_sy;
450
451int g_nframewin_x;
452int g_nframewin_y;
453int g_nframewin_posx;
454int g_nframewin_posy;
455bool g_bframemax;
456
457bool g_bAutoAnchorMark;
458
459int gpIDXn;
460long gStart_LMT_Offset;
461
462wxArrayString *pMessageOnceArray;
463
464bool g_bUseGLL = true;
465
466int g_nCacheLimit;
467int g_memCacheLimit;
468bool g_bGDAL_Debug;
469
470bool g_bCourseUp;
471int g_COGAvgSec = 15; // COG average period (sec.) for Course Up Mode
472double g_COGAvg;
473bool g_bLookAhead;
474bool g_bskew_comp;
475bool g_bopengl;
476bool g_bSoftwareGL;
495bool g_bsmoothpanzoom;
496// toggle for smooth position jumping
497bool g_bSmoothRecenter = true;
498bool g_fog_overzoom;
499double g_overzoom_emphasis_base;
500bool g_oz_vector_scale;
501double g_plus_minus_zoom_factor;
502bool g_bChartBarEx;
503
504bool g_b_legacy_input_filter_behaviour; // Support original input filter
505 // process or new process
506
507PlugInManager *g_pi_manager;
508
509bool g_bDebugGPSD;
510
511bool g_bFullScreenQuilt = true;
512bool g_bQuiltEnable;
513bool g_bQuiltStart;
514
515ChartGroupArray *g_pGroupArray;
516
517S57QueryDialog *g_pObjectQueryDialog;
518
519std::vector<std::string> TideCurrentDataSet;
520wxString g_TCData_Dir;
521
522options *g_options;
523bool g_bDeferredInitDone;
524int options_lastPage = 0;
525int options_subpage = 0;
526
527wxPoint options_lastWindowPos(0, 0);
528wxSize options_lastWindowSize(0, 0);
529
530bool g_bSleep;
531bool g_bsimplifiedScalebar;
532
533int osMajor, osMinor;
534
535bool GetMemoryStatus(int *mem_total, int *mem_used);
536bool g_bHasHwClock;
537
538int g_nAIS_activity_timer;
539
540bool g_bEnableZoomToCursor;
541
542bool g_bTrackActive;
543bool g_bDeferredStartTrack;
544bool g_bHighliteTracks;
545wxColour g_colourTrackLineColour;
546wxString g_default_wp_icon;
547
548ActiveTrack *g_pActiveTrack;
549double g_TrackIntervalSeconds;
550
551int g_cm93_zoom_factor;
552PopUpDSlide *pPopupDetailSlider;
553bool g_bShowDetailSlider;
554int g_detailslider_dialog_x, g_detailslider_dialog_y;
555
556bool g_bUseGreenShip;
557
558wxString g_AW1GUID;
559wxString g_AW2GUID;
560
561bool g_b_overzoom_x = true; // Allow high overzoom
562
563int g_OwnShipIconType;
564double g_n_ownship_length_meters;
565double g_n_ownship_beam_meters;
566double g_n_gps_antenna_offset_y;
567double g_n_gps_antenna_offset_x;
568int g_n_ownship_min_mm;
569
570int g_NeedDBUpdate; // 0 - No update needed, 1 - Update needed because there is
571 // no chart database, inform user, 2 - Start update right
572 // away
573bool g_bPreserveScaleOnX;
574bool g_CanvasHideNotificationIcon;
575
576AboutFrameImpl *g_pAboutDlg;
577About *g_pAboutDlgLegacy;
578
579#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
580wxLocale *plocale_def_lang = 0;
581#endif
582
591wxString g_locale;
592wxString g_localeOverride;
593bool g_b_assume_azerty;
594
595int g_click_stop;
596
597int g_MemFootMB;
598
599bool g_bShowStatusBar;
600
601bool g_bquiting;
602int g_BSBImgDebug;
603
604AISTargetListDialog *g_pAISTargetList;
605int g_AisTargetList_count;
606bool g_bAisTargetList_autosort;
607
608bool g_bFullscreen;
609
610OCPN_AUIManager *g_pauimgr;
611wxAuiDefaultDockArt *g_pauidockart;
612
613wxString g_toolbarConfig = _T("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
614
615ocpnFloatingToolbarDialog *g_MainToolbar;
616int g_maintoolbar_x;
617int g_maintoolbar_y;
618long g_maintoolbar_orient;
619float g_toolbar_scalefactor;
620
621float g_compass_scalefactor;
622bool g_bShowMenuBar;
623bool g_bShowCompassWin;
624
625bool g_benable_rotate;
626
627int g_GPU_MemSize;
628
629wxString g_uiStyle;
630
631// Values returned from WMM_PI for variation computation request.
632// Initialize to invalid so we don't use it if WMM hasn't updated yet
633double gQueryVar = 361.0;
634
635char bells_sound_file_name[2][12] = {"1bells.wav", "2bells.wav"};
636
637int portaudio_initialized;
638
639char nmea_tick_chars[] = {'|', '/', '-', '\\', '|', '/', '-', '\\'};
640
641int g_sticky_chart;
642int g_sticky_projection;
643
644int n_NavMessageShown;
645wxString g_config_version_string;
646
647wxString g_CmdSoundString;
648
663bool g_bRollover;
664
665bool b_inCompressAllCharts;
666bool g_bGLexpert;
667bool g_bUIexpert;
668
669int g_chart_zoom_modifier_raster;
670int g_chart_zoom_modifier_vector;
671
672bool g_bAdvanceRouteWaypointOnArrivalOnly;
673
674bool g_bSpaceDropMark;
675
676wxArrayString g_locale_catalog_array;
677bool b_reloadForPlugins;
678bool g_btrackContinuous;
679
680unsigned int g_canvasConfig;
681bool g_useMUI;
682bool g_bmasterToolbarFull = true;
683
684int g_AndroidVersionCode;
685
686int g_memUsed;
687SENCThreadManager *g_SencThreadManager;
688
689WX_DEFINE_ARRAY_PTR(ChartCanvas *, arrayofCanvasPtr);
690
691arrayofCanvasPtr g_canvasArray;
692wxString g_lastAppliedTemplateGUID;
693
694ChartCanvas *g_focusCanvas;
695ChartCanvas *g_overlayCanvas;
696
697bool b_inCloseWindow;
698bool g_disable_main_toolbar;
699bool g_btenhertz;
700
701#ifdef LINUX_CRASHRPT
702wxCrashPrint g_crashprint;
703#endif
704
705#ifndef __WXMSW__
706sigjmp_buf env; // the context saved by sigsetjmp();
707#endif
708
709// {2C9C45C2-8E7D-4C08-A12D-816BBAE722C0}
710#ifdef __WXMSW__
711DEFINE_GUID(GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81,
712 0x6b, 0xba, 0xe7, 0x22, 0xc0);
713#endif
714
715#ifdef __VISUALC__
716#include <wx/msw/msvcrt.h>
717#endif
718
719#if !defined(NAN)
720static const long long lNaN = 0xfff8000000000000;
721#define NAN (*(double *)&lNaN)
722#endif
723
724// Some static helpers
725void appendOSDirSlash(wxString *pString);
726
727void InitializeUserColors(void);
728void DeInitializeUserColors(void);
729void SetSystemColors(ColorScheme cs);
730
731static bool LoadAllPlugIns(bool load_enabled) {
732 g_Platform->ShowBusySpinner();
733 bool b = PluginLoader::GetInstance()->LoadAllPlugIns(load_enabled);
734 g_Platform->HideBusySpinner();
735 return b;
736}
737
738//------------------------------------------------------------------------------
739// PNG Icon resources
740//------------------------------------------------------------------------------
741
742#if defined(__WXGTK__) || defined(__WXQT__)
743#include "bitmaps/opencpn.xpm"
744#endif
745
746wxString newPrivateFileName(wxString, const char *name,
747 [[maybe_unused]] const char *windowsName) {
748 wxString fname = wxString::FromUTF8(name);
749 wxString filePathAndName;
750
751 filePathAndName = g_Platform->GetPrivateDataDir();
752 if (filePathAndName.Last() != wxFileName::GetPathSeparator())
753 filePathAndName.Append(wxFileName::GetPathSeparator());
754
755#ifdef __WXMSW__
756 wxString fwname = wxString::FromUTF8(windowsName);
757 filePathAndName.Append(fwname);
758#else
759 filePathAndName.Append(fname);
760#endif
761
762 return filePathAndName;
763}
764
765// `Main program` equivalent, creating windows and returning main app frame
766//------------------------------------------------------------------------------
767// MyApp
768//------------------------------------------------------------------------------
769IMPLEMENT_APP(MyApp)
770
771BEGIN_EVENT_TABLE(MyApp, wxApp)
772EVT_ACTIVATE_APP(MyApp::OnActivateApp)
773END_EVENT_TABLE()
774
775static void ActivateRoute(const std::string &guid) {
776 Route *route = g_pRouteMan->FindRouteByGUID(guid);
777 if (!route) {
778 wxLogMessage("Cannot activate guid: no such route");
779 return;
780 }
781 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
782 // If this is an auto-created MOB route, always select the second point
783 // (the MOB)
784 // as the destination.
785 RoutePoint *point;
786 if (wxNOT_FOUND == route->m_RouteNameString.Find("MOB")) {
787 point = g_pRouteMan->FindBestActivatePoint(route, gLat, gLon, gCog, gSog);
788 } else {
789 point = route->GetPoint(2);
790 }
791 g_pRouteMan->ActivateRoute(route, point);
792 if (g_pRouteMan) g_pRouteMan->on_routes_update.Notify();
793 route->m_bRtIsSelected = false;
794}
795
796static void ReverseRoute(const std::string &guid) {
797 Route *route = g_pRouteMan->FindRouteByGUID(guid);
798 if (!route) {
799 wxLogMessage("Cannot activate guid: no such route");
800 return;
801 }
802 route->Reverse();
803 if (g_pRouteMan) g_pRouteMan->on_routes_update.Notify();
804}
805
806void MyApp::InitRestListeners() {
807 auto activate_route = [&](wxCommandEvent ev) {
808 auto guid = ev.GetString().ToStdString();
809 ActivateRoute(guid);
810 };
811 rest_activate_listener.Init(m_rest_server.activate_route, activate_route);
812 auto reverse_route = [&](wxCommandEvent ev) {
813 auto guid = ev.GetString().ToStdString();
814 ReverseRoute(guid);
815 };
816 rest_reverse_listener.Init(m_rest_server.reverse_route, reverse_route);
817}
818
819bool MyApp::OpenFile(const std::string &path) {
820 NavObjectCollection1 nav_objects;
821 auto result = nav_objects.load_file(path.c_str());
822 if (!result) {
823 std::string s(_("Cannot load route or waypoint file: "));
824 s += std::string("\"") + path + "\"";
825 wxMessageBox(s, "OpenCPN", wxICON_WARNING | wxOK);
826 return false;
827 }
828
829 int wpt_dups;
830 // Import with full vizibility of names and objects
831 nav_objects.LoadAllGPXObjects(!nav_objects.IsOpenCPN(), wpt_dups, true);
832
833 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
834 pRouteManagerDialog->UpdateLists();
835 LLBBox box = nav_objects.GetBBox();
836 if (box.GetValid()) {
837 gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
838 }
839 return true;
840}
841
842#ifndef __ANDROID__
843void MyApp::OnInitCmdLine(wxCmdLineParser &parser) {
844 // Add OpenCPN specific command line options. Help message
845 // is hardcoded in kUsage;
846 parser.AddSwitch("h", "help", "", wxCMD_LINE_OPTION_HELP);
847 parser.AddSwitch("p", "portable");
848 parser.AddOption("c", "configdir", "", wxCMD_LINE_VAL_STRING,
849 wxCMD_LINE_PARAM_OPTIONAL);
850 parser.AddSwitch("f", "fullscreen");
851 parser.AddSwitch("G", "no_opengl");
852 parser.AddSwitch("W", "config_wizard");
853 parser.AddSwitch("g", "rebuild_gl_raster_cache");
854 parser.AddSwitch("D", "rebuild_chart_db");
855 parser.AddSwitch("P", "parse_all_enc");
856 parser.AddOption("l", "loglevel");
857 parser.AddOption("u", "unit_test_1", "", wxCMD_LINE_VAL_NUMBER);
858 parser.AddSwitch("U", "unit_test_2");
859 parser.AddParam("import GPX files", wxCMD_LINE_VAL_STRING,
860 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
861 parser.AddSwitch("s", "safe_mode");
862 parser.AddSwitch("r", "remote");
863 parser.AddSwitch("R", "raise");
864 parser.AddSwitch("q", "quit");
865 parser.AddSwitch("e", "get_rest_endpoint");
866 parser.AddOption("o", "open", "", wxCMD_LINE_VAL_STRING,
867 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
868}
869#endif // __ANDROID__
870
872#ifdef __ANDROID__
873static void ParseLoglevel(wxCmdLineParser &parser) {
874 wxLog::SetLogLevel(wxLOG_Message);
875}
876#else
877static void ParseLoglevel(wxCmdLineParser &parser) {
878 const char *strLevel = std::getenv("OPENCPN_LOGLEVEL");
879 strLevel = strLevel ? strLevel : "info";
880 wxString wxLevel;
881 if (parser.Found("l", &wxLevel)) {
882 strLevel = wxLevel.c_str();
883 }
884 wxLogLevel level = OcpnLog::str2level(strLevel);
885 if (level == OcpnLog::LOG_BADLEVEL) {
886 fprintf(stderr, "Bad loglevel %s, using \"info\"", strLevel);
887 level = wxLOG_Info;
888 }
889 wxLog::SetLogLevel(level);
890}
891#endif // __ANDROID__
892
893#ifndef __ANDROID__
894bool MyApp::OnCmdLineHelp(wxCmdLineParser &parser) {
895 std::cout << kUsage;
896 return false;
897}
898#endif
899
900#ifndef __ANDROID__
901bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser) {
902 long number;
903 wxString repo;
904 wxString plugin;
905
906 g_unit_test_2 = parser.Found("unit_test_2");
907 g_bportable = parser.Found("p");
908 g_start_fullscreen = parser.Found("fullscreen");
909 g_bdisable_opengl = parser.Found("no_opengl");
910 g_rebuild_gl_cache = parser.Found("rebuild_gl_raster_cache");
911 g_NeedDBUpdate = parser.Found("rebuild_chart_db") ? 2 : 0;
912 g_parse_all_enc = parser.Found("parse_all_enc");
913 g_config_wizard = parser.Found("config_wizard");
914 if (parser.Found("unit_test_1", &number)) {
915 g_unit_test_1 = static_cast<int>(number);
916 if (g_unit_test_1 == 0) g_unit_test_1 = -1;
917 }
918 safe_mode::set_mode(parser.Found("safe_mode"));
919 ParseLoglevel(parser);
920 wxString wxstr;
921 if (parser.Found("configdir", &wxstr)) {
922 g_configdir = wxstr.ToStdString();
923 fs::path path(g_configdir);
924 if (!fs::exists(path) || !fs::is_directory(path)) {
925 std::cerr << g_configdir << " is not an existing directory.\n";
926 return false;
927 }
928 }
929
930 bool has_start_options = false;
931 static const std::vector<std::string> kStartOptions = {
932 "unit_test_2",
933 "p",
934 "fullscreen",
935 "no_opengl",
936 "rebuild_gl_raster_cache",
937 "rebuild_chart_db",
938 "parse_all_enc",
939 "unit_test_1",
940 "safe_mode",
941 "loglevel"};
942 for (const auto &opt : kStartOptions) {
943 if (parser.Found(opt)) has_start_options = true;
944 }
945 if (has_start_options && parser.Found("remote")) {
946 std::cerr << "this option is not compatible with --remote\n";
947 return false;
948 }
949
950 bool has_remote_options = false;
951 static const std::vector<std::string> kRemoteOptions = {
952 "raise", "quit", "open", "get_rest_endpoint"};
953 for (const auto &opt : kRemoteOptions) {
954 if (parser.Found(opt)) has_remote_options = true;
955 }
956 if (has_remote_options && !parser.Found("remote")) {
957 std::cerr << "This option requires --remote\n";
958 return false;
959 }
960
961 for (size_t paramNr = 0; paramNr < parser.GetParamCount(); ++paramNr)
962 g_params.push_back(parser.GetParam(paramNr).ToStdString());
963
964 wxString optarg;
965 if (!parser.Found("remote"))
966 m_parsed_cmdline = ParsedCmdline();
967 else if (parser.Found("raise"))
968 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
969 else if (parser.Found("quit"))
970 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Quit);
971 else if (parser.Found("get_rest_endpoint"))
972 m_parsed_cmdline = ParsedCmdline(CmdlineAction::GetRestEndpoint);
973 else if (parser.Found("open", &optarg))
974 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Open, optarg.ToStdString());
975 else if (parser.GetParamCount() == 1)
976 m_parsed_cmdline =
977 ParsedCmdline(CmdlineAction::Open, parser.GetParam(0).ToStdString());
978 else if (!has_start_options && !has_remote_options) {
979 // Neither arguments nor options
980 m_parsed_cmdline = ParsedCmdline(CmdlineAction::Raise);
981 }
982 return true;
983}
984#endif // __ANDROID__
985
986#ifdef __WXMSW__
987// Handle any exception not handled by CrashRpt
988// Most probable: Malloc/new failure
989
990bool MyApp::OnExceptionInMainLoop() {
991 wxLogWarning(_T("Caught MainLoopException, continuing..."));
992 return true;
993}
994#endif
995
996void MyApp::OnActivateApp(wxActivateEvent &event) { return; }
997
998static wxStopWatch init_sw;
999
1000int MyApp::OnRun() {
1001 if (m_exitcode != -2) return m_exitcode;
1002 return wxAppConsole::OnRun();
1003}
1004
1005MyApp::MyApp()
1006 : m_checker(InstanceCheck::GetInstance()),
1007 m_rest_server(PINCreateDialog::GetDlgCtx(), RouteCtxFactory(),
1008 g_bportable),
1009 m_usb_watcher(UsbWatchDaemon::GetInstance()),
1010 m_exitcode(-2) {
1011#ifdef __linux__
1012 // Handle e. g., wayland default display -- see #1166.
1013 if (wxGetEnv("WAYLAND_DISPLAY", NULL)) {
1014 setenv("GDK_BACKEND", "x11", 1);
1015 }
1016 setenv(
1017 "mesa_glthread", "false",
1018 1); // Explicitly disable glthread. This may have some impact on OpenGL
1019 // performance, but we know it is problematic for us. See #2889
1020#endif // __linux__
1021}
1022
1023bool MyApp::OnInit() {
1024 if (!wxApp::OnInit()) return false;
1025#ifdef __ANDROID__
1026 androidEnableBackButton(false);
1027 androidEnableOptionItems(false);
1028#endif
1029
1031
1032#if defined(__WXGTK__) && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
1033 // There is a race condition between cairo which is used for text rendering
1034 // by gtk and EGL which without the below code causes a bus error and the
1035 // program aborts before startup
1036 // this hack forces cairo to load right now by rendering some text
1037
1038 wxBitmap bmp(10, 10, -1);
1039 wxMemoryDC dc;
1040 dc.SelectObject(bmp);
1041 dc.DrawText(_T("X"), 0, 0);
1042#endif
1043
1044 // Instantiate the global OCPNPlatform class
1045 g_Platform = new OCPNPlatform;
1046 g_BasePlatform = g_Platform;
1047#ifndef __ANDROID__
1048 // We allow only one instance unless the portable option is used
1049 if (!g_bportable && wxDirExists(g_Platform->GetPrivateDataDir())) {
1050 m_checker.WaitUntilValid();
1051 if (m_checker.IsMainInstance()) {
1052 // Server is created on first call to GetInstance()
1053 if (m_parsed_cmdline.action == CmdlineAction::Skip) {
1054 // Server starts running when referenced.
1055 [[maybe_unused]] auto &server = LocalServerApi::GetInstance();
1056 } else {
1057 std::cerr << "No remote opencpn found. Giving up.\n";
1058 m_exitcode = 1;
1059 return true;
1060 }
1061 } else {
1062 std::unique_ptr<LocalClientApi> client;
1063 try {
1064 client = LocalClientApi::GetClient();
1065 } catch (LocalApiException &ie) {
1066 WARNING_LOG << "Ipc client exception: " << ie.str();
1067 // If we get here it means that the instance_chk found another
1068 // running instance. But that instance is for some reason not
1069 // reachable. The safe thing to do is delete the lockfile and exit.
1070 // Next start will proceed normally. This may leave a zombie OpenCPN,
1071 // but at least O starts.
1072 m_checker.CleanUp();
1073 wxMessageBox(_("Sorry, an existing instance of OpenCPN may be too busy "
1074 "to respond.\nPlease retry."),
1075 "OpenCPN", wxICON_INFORMATION | wxOK);
1076 m_exitcode = 2;
1077 return true; // main program quiet exit.
1078 }
1079 if (client) {
1080 auto result = client->HandleCmdline(m_parsed_cmdline.action,
1081 m_parsed_cmdline.arg);
1082 if (result.first) {
1083 m_exitcode = 0;
1084 } else {
1085 wxLogDebug("Error running remote command: %s", result.second.c_str());
1086 m_exitcode = 1;
1087 }
1088 return true;
1089 }
1090 }
1091 }
1092#endif // __ANDROID__
1093
1094 if (getenv("OPENCPN_FATAL_ERROR") != 0) {
1095 wxLogFatalError(getenv("OPENCPN_FATAL_ERROR"));
1096 }
1097
1098#ifndef __ANDROID__
1099 // Check if last run failed, set up safe_mode.
1100 if (!safe_mode::get_mode()) {
1102 }
1103#endif
1104
1105 // Perform first stage initialization
1106 OCPNPlatform::Initialize_1();
1107
1108 // Set the name of the app as displayed to the user.
1109 // This is necessary at least on OS X, for the capitalisation to be correct in
1110 // the system menus.
1111 MyApp::SetAppDisplayName("OpenCPN");
1112
1113 // Seed the random number generator
1114 wxDateTime x = wxDateTime::UNow();
1115 long seed = x.GetMillisecond();
1116 seed *= x.GetTicks();
1117 srand(seed);
1118
1119 // Fulup: force floating point to use dot as separation.
1120 // This needs to be set early to catch numerics in config file.
1121 setlocale(LC_NUMERIC, "C");
1122
1123 g_start_time = wxDateTime::Now();
1124
1125 g_loglast_time = g_start_time;
1126 g_loglast_time.MakeGMT();
1127 g_loglast_time.Subtract(
1128 wxTimeSpan(0, 29, 0, 0)); // give 1 minute for GPS to get a fix
1129
1130 AnchorPointMinDist = 5.0;
1131
1132 // Init the private memory manager
1133 malloc_max = 0;
1134
1135 // Record initial memory status
1136 GetMemoryStatus(&g_mem_total, &g_mem_initial);
1137
1138 // Set up default FONT encoding, which should have been done by wxWidgets some
1139 // time before this......
1140 wxFont temp_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
1141 wxFONTWEIGHT_NORMAL, FALSE, wxString(_T("")),
1142 wxFONTENCODING_SYSTEM);
1143 temp_font.SetDefaultEncoding(wxFONTENCODING_SYSTEM);
1144
1145 // Start the Notification Manager and remove old persisted messages
1146 auto &noteman = NotificationManager::GetInstance();
1147 noteman.ScrubNotificationDirectory(30);
1148
1149 // Establish Log File location
1150 if (!g_Platform->InitializeLogFile()) {
1151 return false;
1152 };
1153
1154#ifdef __WXMSW__
1155
1156 // Un-comment the following to establish a separate console window as a
1157 // target for printf() in Windows RedirectIOToConsole();
1158
1159#endif
1160
1161 // Send init message
1162 wxLogMessage(_T("\n\n________\n"));
1163
1164 wxDateTime now = wxDateTime::Now();
1165 LOG_INFO("------- OpenCPN version %s restarted at %s -------\n", VERSION_FULL,
1166 now.FormatISODate().mb_str().data());
1167 wxLogLevel level = wxLog::GetLogLevel();
1168 LOG_INFO("Using loglevel %s", OcpnLog::level2str(level).c_str());
1169
1170 wxString wxver(wxVERSION_STRING);
1171 wxver.Prepend(_T("wxWidgets version: "));
1172
1173 wxPlatformInfo platforminfo = wxPlatformInfo::Get();
1174
1175 wxString os_name;
1176#ifndef __ANDROID__
1177 os_name = platforminfo.GetOperatingSystemIdName();
1178#else
1179 os_name = platforminfo.GetOperatingSystemFamilyName();
1180#endif
1181
1182 wxString platform = os_name + _T(" ") + platforminfo.GetArchName() + _T(" ") +
1183 platforminfo.GetPortIdName();
1184
1185 wxLogMessage(wxver + _T(" ") + platform);
1186
1187 ::wxGetOsVersion(&osMajor, &osMinor);
1188 wxString osVersionMsg;
1189 osVersionMsg.Printf(_T("OS Version reports as: %d.%d"), osMajor, osMinor);
1190 wxLogMessage(osVersionMsg);
1191
1192 wxLogMessage(_T("MemoryStatus: mem_total: %d mb, mem_initial: %d mb"),
1193 g_mem_total / 1024, g_mem_initial / 1024);
1194
1195 OCPN_OSDetail *detail = g_Platform->GetOSDetail();
1196 wxString msgplat;
1197 wxString like0;
1198 if (!detail->osd_names_like.empty())
1199 like0 = detail->osd_names_like[0].c_str();
1200 msgplat.Printf("OCPN_OSDetail: %s ; %s ; %s ; %s ; %s",
1201 detail->osd_arch.c_str(), detail->osd_name.c_str(),
1202 detail->osd_version.c_str(), detail->osd_ID.c_str(),
1203 like0.mb_str());
1204 wxLogMessage(msgplat);
1205
1206 wxString imsg = _T("SData_Locn is ");
1207 imsg += g_Platform->GetSharedDataDir();
1208 wxLogMessage(imsg);
1209
1210 // Initialize embedded PNG icon graphics
1211 ::wxInitAllImageHandlers();
1212
1213#ifdef __WXQT__
1214 // Now we can configure the Qt StyleSheets, if present
1215 prepareAndroidStyleSheets();
1216#endif
1217
1218 // Create some static strings
1219 pInit_Chart_Dir = new wxString();
1220
1221 // Establish an empty ChartCroupArray
1222 g_pGroupArray = new ChartGroupArray;
1223
1224 imsg = _T("PrivateDataDir is ");
1225 imsg += g_Platform->GetPrivateDataDir();
1226 wxLogMessage(imsg);
1227
1228 // Create an array string to hold repeating messages, so they don't
1229 // overwhelm the log
1230 pMessageOnceArray = new wxArrayString;
1231
1232 // Init the Route Manager
1233 g_pRouteMan =
1234 new Routeman(RoutePropDlg::GetDlgCtx(), RoutemanGui::GetDlgCtx());
1235
1236 // Init the Selectable Route Items List
1237 pSelect = new Select();
1238 pSelect->SetSelectPixelRadius(12);
1239
1240 // Init the Selectable Tide/Current Items List
1241 pSelectTC = new Select();
1242 // Increase the select radius for tide/current stations
1243 pSelectTC->SetSelectPixelRadius(25);
1244
1245 // Init the Selectable AIS Target List
1246 pSelectAIS = new Select();
1247 pSelectAIS->SetSelectPixelRadius(12);
1248
1249 // Initially AIS display is always on
1250 g_bShowAIS = true;
1251 g_pais_query_dialog_active = NULL;
1252
1253 // Who am I?
1254 g_hostname = ::wxGetHostName();
1255 if (g_hostname.IsEmpty()) g_hostname = wxGetUserName();
1256#ifdef __ANDROID__
1257 androidGetDeviceInfo();
1258 g_hostname = wxString("Android-") + g_android_Device_Model;
1259 g_hostname.Replace(" ", "-", true);
1260#endif
1261
1262 // A Portabel need a unique mDNS data hostname to share routes.
1263 if (g_bportable) {
1264 wxString p("Portable-");
1265 g_hostname = p + g_hostname;
1266 }
1267
1268 // Initialize some lists
1269 // Layers
1270 pLayerList = new LayerList;
1271 // Routes
1272 pRouteList = new RouteList;
1273
1274 // (Optionally) Capture the user and file(effective) ids
1275 // Some build environments may need root privileges for hardware
1276 // port I/O, as in the NMEA data input class. Set that up here.
1277
1278#ifndef __WXMSW__
1279#ifdef PROBE_PORTS__WITH_HELPER
1280 user_user_id = getuid();
1281 file_user_id = geteuid();
1282#endif
1283#endif
1284
1285 bool b_initial_load = false;
1286
1287 wxFileName config_test_file_name(g_Platform->GetConfigFileName());
1288 if (config_test_file_name.FileExists())
1289 wxLogMessage(_T("Using existing Config_File: ") +
1290 g_Platform->GetConfigFileName());
1291 else {
1292 {
1293 wxLogMessage(_T("Creating new Config_File: ") +
1294 g_Platform->GetConfigFileName());
1295
1296 b_initial_load = true;
1297
1298 if (true !=
1299 config_test_file_name.DirExists(config_test_file_name.GetPath()))
1300 if (!config_test_file_name.Mkdir(config_test_file_name.GetPath()))
1301 wxLogMessage(_T("Cannot create config file directory for ") +
1302 g_Platform->GetConfigFileName());
1303 }
1304 }
1305
1306 // Open/Create the Config Object
1307 pConfig = g_Platform->GetConfigObject();
1308 InitBaseConfig(pConfig);
1309 pConfig->LoadMyConfig();
1310
1311 // Override for some safe and nice default values if the config file was
1312 // created from scratch
1313 if (b_initial_load) g_Platform->SetDefaultOptions();
1314
1315 g_Platform->applyExpertMode(g_bUIexpert);
1316
1317 // Now initialize UI Style.
1318 g_StyleManager = new ocpnStyle::StyleManager();
1319
1320 // if(g_useMUI)
1321 // g_uiStyle = _T("MUI_flat");
1322
1323 g_StyleManager->SetStyle(_T("MUI_flat"));
1324 if (!g_StyleManager->IsOK()) {
1325 wxString msg = _("Failed to initialize the user interface. ");
1326 msg << _("OpenCPN cannot start. ");
1327 msg << _("The necessary configuration files were not found. ");
1328 msg << _("See the log file at ") << g_Platform->GetLogFileName()
1329 << _(" for details.") << _T("\n\n");
1330 msg << g_Platform->GetSharedDataDir();
1331
1332 wxMessageDialog w(NULL, msg, _("Failed to initialize the user interface. "),
1333 wxCANCEL | wxICON_ERROR);
1334 w.ShowModal();
1335 exit(EXIT_FAILURE);
1336 }
1337
1338 if (g_useMUI) {
1339 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
1340 if (style) style->chartStatusWindowTransparent = true;
1341 }
1342
1343 // Init the WayPoint Manager
1344 pWayPointMan = NULL;
1345
1346 g_display_size_mm = wxMax(50, g_Platform->GetDisplaySizeMM());
1347 wxString msg;
1348 msg.Printf(_T("Detected display size (horizontal): %d mm"),
1349 (int)g_display_size_mm);
1350 wxLogMessage(msg);
1351
1352 // User override....
1353 if (g_config_display_size_manual &&
1354 g_config_display_size_mm.size() > g_current_monitor &&
1355 g_config_display_size_mm[g_current_monitor] > 0) {
1356 g_display_size_mm = g_config_display_size_mm[g_current_monitor];
1357 wxString msg;
1358 msg.Printf(_T("Display size (horizontal) config override: %d mm"),
1359 (int)g_display_size_mm);
1360 wxLogMessage(msg);
1361 g_Platform->SetDisplaySizeMM(g_current_monitor, g_display_size_mm);
1362 }
1363
1364 g_display_size_mm = wxMax(50, g_display_size_mm);
1365
1366 if (g_btouch) {
1367 int SelectPixelRadius = 50;
1368
1369 pSelect->SetSelectPixelRadius(SelectPixelRadius);
1370 pSelectTC->SetSelectPixelRadius(wxMax(25, SelectPixelRadius));
1371 pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
1372 }
1373
1374 // Is this the first run after a clean installation?
1375 if (!n_NavMessageShown) {
1376 g_bFirstRun = true;
1377 }
1378
1379 // Now we can set the locale
1380 // using wxWidgets/gettext methodology....
1381
1382#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
1383
1384 // Where are the opencpn.mo files?
1385 g_Platform->SetLocaleSearchPrefixes();
1386
1387 wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
1388
1389 imsg = _T("System default Language: ") + def_lang_canonical;
1390 wxLogMessage(imsg);
1391
1392 wxString cflmsg = _T("Config file language: ") + g_locale;
1393 wxLogMessage(cflmsg);
1394
1395 if (g_locale.IsEmpty()) {
1396 g_locale = def_lang_canonical;
1397 cflmsg =
1398 _T("Config file language empty, using system default: ") + g_locale;
1399 wxLogMessage(cflmsg);
1400 }
1401
1402 // Make any adjustments necessary
1403 g_locale = g_Platform->GetAdjustedAppLocale();
1404 cflmsg = _T("Adjusted App language: ") + g_locale;
1405 wxLogMessage(cflmsg);
1406
1407 // Set the desired locale
1408 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
1409
1410 imsg = _T("Opencpn language set to: ");
1411 imsg += g_locale;
1412 wxLogMessage(imsg);
1413
1414 // French language locale is assumed to include the AZERTY keyboard
1415 // This applies to either the system language, or to OpenCPN language
1416 // selection
1417 if (g_locale == _T("fr_FR")) g_b_assume_azerty = true;
1418#else
1419 wxLogMessage(_T("wxLocale support not available"));
1420#endif
1421
1422#ifndef __ANDROID__
1423 // Now that locale is established, possibly run the startup wizard.
1424 if (g_config_wizard || b_initial_load) {
1425 FirstUseWizImpl wiz(gFrame, pConfig);
1426 auto res = wiz.Run();
1427 if (res) {
1428 g_NeedDBUpdate = 2;
1429 }
1430 }
1431#endif
1432
1433 // Instantiate and initialize the Config Manager
1434 ConfigMgr::Get();
1435
1436 // Is this an upgrade?
1437 wxString vs = wxString("Version ") + VERSION_FULL + " Build " + VERSION_DATE;
1438 g_bUpgradeInProcess = (vs != g_config_version_string);
1439
1440 g_Platform->SetUpgradeOptions(vs, g_config_version_string);
1441
1442 // log deferred log restart message, if it exists.
1443 if (!g_Platform->GetLargeLogMessage().IsEmpty()) {
1444 wxLogMessage(g_Platform->GetLargeLogMessage());
1445 }
1446
1447 // Validate OpenGL functionality, if selected
1448#ifndef ocpnUSE_GL
1449 g_bdisable_opengl = true;
1450 ;
1451#endif
1452
1453 if (g_bdisable_opengl) g_bopengl = false;
1454
1455#if defined(__linux__) && !defined(__ANDROID__)
1456 if (g_bSoftwareGL) {
1457 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
1458 }
1459#endif
1460
1461 // FIXMW (dave) move to frame
1462 // g_bTransparentToolbarInOpenGLOK = isTransparentToolbarInOpenGLOK();
1463
1464 // On Windows platforms, establish a default cache managment policy
1465 // as allowing OpenCPN a percentage of available physical memory,
1466 // not to exceed 1 GB
1467 // Note that this logic implies that Windows platforms always use
1468 // the memCacheLimit policy, and never use the fallback nCacheLimit policy
1469#ifdef __WXMSW__
1470 if (0 == g_memCacheLimit) g_memCacheLimit = (int)(g_mem_total * 0.5);
1471 g_memCacheLimit =
1472 wxMin(g_memCacheLimit, 1024 * 1024); // math in kBytes, Max is 1 GB
1473#else
1474 // All other platforms will use the nCacheLimit policy
1475 // sinc on linux it is impossible to accurately measure the application memory
1476 // footprint without expensive methods such as malloc/free tracking, and such
1477
1478 g_memCacheLimit = 0;
1479 if (0 == g_nCacheLimit) // allow config file override
1480 g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
1481#endif
1482
1483 // Establish location and name of chart database
1484 ChartListFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(),
1485 "chartlist.dat", "CHRTLIST.DAT");
1486
1487 // Establish location and name of AIS MMSI -> Target Name mapping
1488 AISTargetNameFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(),
1489 "mmsitoname.csv", "MMSINAME.CSV");
1490
1491 // Establish guessed location of chart tree
1492 if (pInit_Chart_Dir->IsEmpty()) {
1493 wxStandardPaths &std_path = g_Platform->GetStdPaths();
1494
1495 if (!g_bportable)
1496#ifndef __ANDROID__
1497 pInit_Chart_Dir->Append(std_path.GetDocumentsDir());
1498#else
1499 pInit_Chart_Dir->Append(androidGetExtStorageDir());
1500#endif
1501 }
1502
1503 InitRestListeners();
1504
1505 // Establish the GSHHS Dataset location
1506 gDefaultWorldMapLocation = "gshhs";
1507 gDefaultWorldMapLocation.Prepend(g_Platform->GetSharedDataDir());
1508 gDefaultWorldMapLocation.Append(wxFileName::GetPathSeparator());
1509 if (gWorldMapLocation == wxEmptyString) {
1510 gWorldMapLocation = gDefaultWorldMapLocation;
1511 }
1512
1513 // Check the global Tide/Current data source array
1514 // If empty, preset default (US + ROW) data sources
1515 wxString default_tcdata0 =
1516 (g_Platform->GetSharedDataDir() + _T("tcdata") +
1517 wxFileName::GetPathSeparator() + _T("harmonics-dwf-20210110-free.tcd"));
1518 wxString default_tcdata1 =
1519 (g_Platform->GetSharedDataDir() + _T("tcdata") +
1520 wxFileName::GetPathSeparator() + _T("HARMONICS_NO_US.IDX"));
1521
1522 if (TideCurrentDataSet.empty()) {
1523 TideCurrentDataSet.push_back(
1524 g_Platform->NormalizePath(default_tcdata0).ToStdString());
1525 TideCurrentDataSet.push_back(
1526 g_Platform->NormalizePath(default_tcdata1).ToStdString());
1527 }
1528
1529 // Check the global AIS alarm sound file
1530 // If empty, preset default
1531 if (g_sAIS_Alert_Sound_File.IsEmpty()) {
1532 wxString default_sound =
1533 (g_Platform->GetSharedDataDir() + _T("sounds") +
1534 wxFileName::GetPathSeparator() + _T("2bells.wav"));
1535 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
1536 }
1537
1538 gpIDXn = 0;
1539
1540 g_Platform->Initialize_2();
1541
1542 // Set up the frame initial visual parameters
1543 // Default size, resized later
1544 wxSize new_frame_size(-1, -1);
1545 int cx, cy, cw, ch;
1546 ::wxClientDisplayRect(&cx, &cy, &cw, &ch);
1547
1548 InitializeUserColors();
1549
1550 auto style = g_StyleManager->GetCurrentStyle();
1551 auto bitmap = new wxBitmap(style->GetIcon("default_pi", 32, 32));
1552 if (bitmap->IsOk())
1553 PluginLoader::GetInstance()->SetPluginDefaultIcon(bitmap);
1554 else
1555 wxLogWarning("Cannot initiate plugin default jigsaw icon.");
1556
1557 if ((g_nframewin_x > 100) && (g_nframewin_y > 100) && (g_nframewin_x <= cw) &&
1558 (g_nframewin_y <= ch))
1559 new_frame_size.Set(g_nframewin_x, g_nframewin_y);
1560 else
1561 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1562
1563 // Try to detect any change in physical screen configuration
1564 // This can happen when drivers are changed, for instance....
1565 // and can confuse the WUI layout perspective stored in the config file.
1566 // If detected, force a nominal window size and position....
1567 if ((g_lastClientRectx != cx) || (g_lastClientRecty != cy) ||
1568 (g_lastClientRectw != cw) || (g_lastClientRecth != ch)) {
1569 new_frame_size.Set(cw * 7 / 10, ch * 7 / 10);
1570 g_bframemax = false;
1571 }
1572
1573 g_lastClientRectx = cx;
1574 g_lastClientRecty = cy;
1575 g_lastClientRectw = cw;
1576 g_lastClientRecth = ch;
1577
1578 // Validate config file position
1579 wxPoint position(0, 0);
1580 wxSize dsize = wxGetDisplaySize();
1581
1582#ifdef __WXMAC__
1583 g_nframewin_posy = wxMax(g_nframewin_posy, 22);
1584#endif
1585
1586 if ((g_nframewin_posx < dsize.x) && (g_nframewin_posy < dsize.y))
1587 position = wxPoint(g_nframewin_posx, g_nframewin_posy);
1588
1589#ifdef __WXMSW__
1590 // Support MultiMonitor setups which can allow negative window positions.
1591 RECT frame_rect;
1592 frame_rect.left = position.x;
1593 frame_rect.top = position.y;
1594 frame_rect.right = position.x + new_frame_size.x;
1595 frame_rect.bottom = position.y + new_frame_size.y;
1596
1597 // If the requested frame window does not intersect any installed monitor,
1598 // then default to simple primary monitor positioning.
1599 if (NULL == MonitorFromRect(&frame_rect, MONITOR_DEFAULTTONULL))
1600 position = wxPoint(10, 10);
1601#endif
1602
1603#ifdef __WXOSX__
1604 // Support MultiMonitor setups which can allow negative window positions.
1605 const wxPoint ptScreen(position.x, position.y);
1606 const int displayIndex = wxDisplay::GetFromPoint(ptScreen);
1607
1608 if (displayIndex == wxNOT_FOUND) position = wxPoint(10, 30);
1609#endif
1610
1611 g_nframewin_posx = position.x;
1612 g_nframewin_posy = position.y;
1613
1614#ifdef __ANDROID__
1615 wxSize asz = getAndroidDisplayDimensions();
1616 ch = asz.y;
1617 cw = asz.x;
1618 // qDebug() << cw << ch;
1619
1620 if ((cw > 200) && (ch > 200))
1621 new_frame_size.Set(cw, ch);
1622 else
1623 new_frame_size.Set(800, 400);
1624#endif
1625
1626 // For Windows and GTK, provide the expected application Minimize/Close bar
1627 long app_style = wxDEFAULT_FRAME_STYLE;
1628 app_style |= wxWANTS_CHARS;
1629
1630 // Create the main frame window
1631
1632 // Strip the commit SHA number from the string to be shown in frame title.
1633 wxString short_version_name = wxString(PACKAGE_VERSION).BeforeFirst('+');
1634 wxString myframe_window_title =
1635 wxString(wxT("OpenCPN ") + short_version_name);
1636
1637 if (g_bportable) {
1638 myframe_window_title += _(" -- [Portable(-p) executing from ");
1639 myframe_window_title += g_Platform->GetHomeDir();
1640 myframe_window_title += _T("]");
1641 }
1642
1643 wxString fmsg;
1644 fmsg.Printf(_T("Creating MyFrame...size(%d, %d) position(%d, %d)"),
1645 new_frame_size.x, new_frame_size.y, position.x, position.y);
1646 wxLogMessage(fmsg);
1647
1648 gFrame = new MyFrame(NULL, myframe_window_title, position, new_frame_size,
1649 app_style);
1650 wxTheApp->SetTopWindow(gFrame);
1651
1652 // Do those platform specific initialization things that need gFrame
1653 g_Platform->Initialize_3();
1654
1655 // Initialize the Plugin Manager
1656 g_pi_manager = new PlugInManager(gFrame);
1657
1658 // g_pauimgr = new wxAuiManager;
1659 g_pauimgr = new OCPN_AUIManager;
1660 g_pauidockart = new wxAuiDefaultDockArt;
1661 g_pauimgr->SetArtProvider(g_pauidockart);
1662 g_pauimgr->SetDockSizeConstraint(.9, .9);
1663
1664 // g_pauimgr->SetFlags(g_pauimgr->GetFlags() | wxAUI_MGR_LIVE_RESIZE);
1665
1666 // tell wxAuiManager to manage the frame
1667 g_pauimgr->SetManagedWindow(gFrame);
1668
1669 gFrame->CreateCanvasLayout();
1670
1671 // gFrame->RequestNewMasterToolbar( true );
1672
1673 gFrame->SetChartUpdatePeriod(); // Reasonable default
1674
1675 gFrame->Enable();
1676
1677 gFrame->GetPrimaryCanvas()->SetFocus();
1678
1679 pthumbwin = new ThumbWin(gFrame->GetPrimaryCanvas());
1680
1681 gFrame->ApplyGlobalSettings(false); // done once on init with resize
1682
1683 gFrame->SetAllToolbarScale();
1684
1685 // Show the frame
1686 gFrame->Show(TRUE);
1687 Yield(); // required for Gnome 45
1688
1689 gFrame->SetAndApplyColorScheme(global_color_scheme);
1690
1691 if (g_bframemax) gFrame->Maximize(true);
1692
1693#ifdef __ANDROID__
1694 if (g_bresponsive && (gFrame->GetPrimaryCanvas()->GetPixPerMM() > 4.0))
1695 gFrame->Maximize(true);
1696#endif
1697
1698 // Yield to pick up the OnSize() calls that result from Maximize()
1699 Yield();
1700
1701 // Build the initial chart dir array
1702 ArrayOfCDI ChartDirArray;
1703 pConfig->LoadChartDirArray(ChartDirArray);
1704
1705 // Windows installer may have left hints regarding the initial chart dir
1706 // selection
1707#ifdef __WXMSW__
1708 if (g_bFirstRun && (ChartDirArray.GetCount() == 0)) {
1709 int ndirs = 0;
1710
1711 wxRegKey RegKey(wxString(_T("HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN")));
1712 if (RegKey.Exists()) {
1713 wxLogMessage(
1714 _("Retrieving initial Chart Directory set from Windows Registry"));
1715 wxString dirs;
1716 RegKey.QueryValue(wxString(_T("ChartDirs")), dirs);
1717
1718 wxStringTokenizer tkz(dirs, _T(";"));
1719 while (tkz.HasMoreTokens()) {
1720 wxString token = tkz.GetNextToken();
1721
1722 ChartDirInfo cdi;
1723 cdi.fullpath = token.Trim();
1724 cdi.magic_number = _T("");
1725
1726 ChartDirArray.Add(cdi);
1727 ndirs++;
1728 }
1729 }
1730
1731 if (g_bportable) {
1732 ChartDirInfo cdi;
1733 cdi.fullpath = _T("charts");
1734 cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
1735 cdi.magic_number = _T("");
1736 ChartDirArray.Add(cdi);
1737 ndirs++;
1738 }
1739
1740 if (ndirs) pConfig->UpdateChartDirs(ChartDirArray);
1741 }
1742#endif
1743
1744 // If the ChartDirArray is empty at this point, any existing chart database
1745 // file must be declared invalid, So it is best to simply delete it if
1746 // present.
1747 // TODO There is a possibility of recreating the dir list from the
1748 // database itself......
1749
1750 if (!ChartDirArray.GetCount())
1751 if (::wxFileExists(ChartListFileName)) ::wxRemoveFile(ChartListFileName);
1752
1753 // Try to load the current chart list Data file
1754 ChartData = new ChartDB();
1755 if (g_NeedDBUpdate == 0 &&
1756 !ChartData->LoadBinary(ChartListFileName, ChartDirArray)) {
1757 g_NeedDBUpdate = 1;
1758 }
1759
1760 // Verify any saved chart database startup index
1761 if (g_restore_dbindex >= 0) {
1762 if (ChartData->GetChartTableEntries() == 0)
1763 g_restore_dbindex = -1;
1764
1765 else if (g_restore_dbindex > (ChartData->GetChartTableEntries() - 1))
1766 g_restore_dbindex = 0;
1767 }
1768
1769 // Apply the inital Group Array structure to the chart database
1770 ChartData->ApplyGroupArray(g_pGroupArray);
1771
1772 // All set to go.....
1773
1774 // Process command line option to rebuild cache
1775#ifdef ocpnUSE_GL
1776 extern ocpnGLOptions g_GLOptions;
1777
1778 if (g_rebuild_gl_cache && g_bopengl && g_GLOptions.m_bTextureCompression &&
1779 g_GLOptions.m_bTextureCompressionCaching) {
1780 gFrame->ReloadAllVP(); // Get a nice chart background loaded
1781
1782 // Turn off the toolbar as a clear signal that the system is busy right
1783 // now.
1784 // Note: I commented this out because the toolbar never comes back for me
1785 // and is unusable until I restart opencpn without generating the cache
1786 // if( g_MainToolbar )
1787 // g_MainToolbar->Hide();
1788
1789 if (g_glTextureManager) g_glTextureManager->BuildCompressedCache();
1790 }
1791#endif
1792
1793 // FIXME (dave)
1794 // move method to frame
1795 // if (g_parse_all_enc) ParseAllENC(gFrame);
1796
1797 // establish GPS timeout value as multiple of frame timer
1798 // This will override any nonsense or unset value from the config file
1799 if ((gps_watchdog_timeout_ticks > 60) || (gps_watchdog_timeout_ticks <= 0))
1800 gps_watchdog_timeout_ticks = (GPS_TIMEOUT_SECONDS * 1000) / TIMER_GFRAME_1;
1801
1802 wxString dogmsg;
1803 dogmsg.Printf(_T("GPS Watchdog Timeout is: %d sec."),
1804 gps_watchdog_timeout_ticks);
1805 wxLogMessage(dogmsg);
1806
1807 sat_watchdog_timeout_ticks = gps_watchdog_timeout_ticks;
1808
1809 g_priSats = 99;
1810
1811 // Most likely installations have no ownship heading information
1812 g_bVAR_Rx = false;
1813
1814 // Start up a new track if enabled in config file
1815 if (g_bTrackCarryOver) g_bDeferredStartTrack = true;
1816
1817 pAnchorWatchPoint1 = NULL;
1818 pAnchorWatchPoint2 = NULL;
1819
1820 Yield();
1821
1822 gFrame->DoChartUpdate();
1823
1824 FontMgr::Get()
1825 .ScrubList(); // Clean the font list, removing nonsensical entries
1826
1827 gFrame->ReloadAllVP(); // once more, and good to go
1828
1829 gFrame->Refresh(false);
1830 gFrame->Raise();
1831
1832 gFrame->GetPrimaryCanvas()->Enable();
1833 gFrame->GetPrimaryCanvas()->SetFocus();
1834
1835 // This little hack fixes a problem seen with some UniChrome OpenGL drivers
1836 // We need a deferred resize to get glDrawPixels() to work right.
1837 // So we set a trigger to generate a resize after 5 seconds....
1838 // See the "UniChrome" hack elsewhere
1839#ifdef ocpnUSE_GL
1840 if (!g_bdisable_opengl) {
1841 glChartCanvas *pgl =
1842 (glChartCanvas *)gFrame->GetPrimaryCanvas()->GetglCanvas();
1843 if (pgl &&
1844 (pgl->GetRendererString().Find(_T("UniChrome")) != wxNOT_FOUND)) {
1845 gFrame->m_defer_size = gFrame->GetSize();
1846 gFrame->SetSize(gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y);
1847 g_pauimgr->Update();
1848 gFrame->m_bdefer_resize = true;
1849 }
1850 }
1851#endif
1852
1853 // Horrible Hack (tm): Make sure the RoutePoint destructor can invoke
1854 // glDeleteTextures. Truly awful.
1855#ifdef ocpnUSE_GL
1856 if (g_bopengl)
1857 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {
1858 glDeleteTextures(n, texts);
1859 };
1860#else
1861 RoutePoint::delete_gl_textures = [](unsigned n, const unsigned *texts) {};
1862#endif
1863
1864 if (g_start_fullscreen) gFrame->ToggleFullScreen();
1865
1866#ifdef __ANDROID__
1867 // We need a resize to pick up height adjustment after building android
1868 // ActionBar
1869 gFrame->SetSize(getAndroidDisplayDimensions());
1870 androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow ? 1 : 0, true);
1871#endif
1872
1873 gFrame->Raise();
1874 gFrame->GetPrimaryCanvas()->Enable();
1875 gFrame->GetPrimaryCanvas()->SetFocus();
1876
1877 // Setup Tides/Currents to settings present at last shutdown
1878 // TODO
1879 // gFrame->ShowTides( g_bShowTide );
1880 // gFrame->ShowCurrents( g_bShowCurrent );
1881
1882 // Start up the ticker....
1883 gFrame->FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
1884
1885 // Start up the ViewPort Rotation angle Averaging Timer....
1886 gFrame->FrameCOGTimer.Start(2000, wxTIMER_CONTINUOUS);
1887
1888 // Start up the Ten Hz timer....
1889 gFrame->FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
1890
1891 // wxLogMessage( wxString::Format(_T("OpenCPN Initialized in %ld ms."),
1892 // init_sw.Time() ) );
1893
1894 OCPNPlatform::Initialize_4();
1895
1896#ifdef __ANDROID__
1897 androidHideBusyIcon();
1898#endif
1899 wxLogMessage(
1900 wxString::Format(_("OpenCPN Initialized in %ld ms."), init_sw.Time()));
1901
1902 wxMilliSleep(500);
1903
1904#ifdef __ANDROID__
1905 // We defer the startup message to here to allow the app frame to be
1906 // contructed, thus avoiding a dialog with NULL parent which might not work
1907 // on some devices.
1908 if (!n_NavMessageShown || (vs != g_config_version_string) ||
1909 (g_AndroidVersionCode != androidGetVersionCode())) {
1910 // qDebug() << "Showing NavWarning";
1911 wxMilliSleep(500);
1912
1913 if (!ShowNavWarning()) {
1914 qDebug() << "Closing due to NavWarning Cancel";
1915 gFrame->Close();
1916 androidTerminate();
1917 return true;
1918 }
1919
1920 n_NavMessageShown = 1;
1921 }
1922
1923 // Finished with upgrade checking, so persist the currect Version Code
1924 g_AndroidVersionCode = androidGetVersionCode();
1925 qDebug() << "Persisting Version Code: " << g_AndroidVersionCode;
1926#else
1927 // Send the Welcome/warning message if it has never been sent before,
1928 // or if the version string has changed at all
1929 // We defer until here to allow for localization of the message
1930 if (!n_NavMessageShown || (vs != g_config_version_string)) {
1931 if (!ShowNavWarning()) return false;
1932 n_NavMessageShown = 1;
1933 pConfig->Flush();
1934 }
1935#endif
1936
1937 // As an a.e. Raspberry does not have a hardwareclock we will have some
1938 // problems with date/time setting
1939 g_bHasHwClock = true; // by default most computers do have a hwClock
1940#if defined(__UNIX__) && !defined(__ANDROID__)
1941 struct stat buffer;
1942 g_bHasHwClock =
1943 ((stat("/dev/rtc", &buffer) == 0) || (stat("/dev/rtc0", &buffer) == 0) ||
1944 (stat("/dev/misc/rtc", &buffer) == 0));
1945#endif
1946
1947 g_config_version_string = vs;
1948
1949 // The user accepted the "not for navigation" nag, so persist it here...
1950 pConfig->UpdateSettings();
1951
1952 // Start delayed initialization chain after some milliseconds
1953 gFrame->InitTimer.Start(5, wxTIMER_CONTINUOUS);
1954
1955 g_pauimgr->Update();
1956
1957 for (auto *cp : TheConnectionParams()) {
1958 if (cp->bEnabled) {
1959 if (cp->GetDSPort().Contains("Serial")) {
1960 std::string port(cp->Port.ToStdString());
1961 CheckSerialAccess(gFrame, port);
1962 }
1963 }
1964 }
1965 CheckDongleAccess(gFrame);
1966
1967 // Initialize the CommBridge
1968 m_comm_bridge.Initialize();
1969
1970 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
1971
1972 // If network connection is available, start the server and mDNS client
1973 if (ipv4_addrs.size()) {
1974 std::string ipAddr = ipv4_addrs[0];
1975
1976 wxString data_dir = g_Platform->GetPrivateDataDir();
1977 if (data_dir.Last() != wxFileName::GetPathSeparator())
1978 data_dir.Append(wxFileName::GetPathSeparator());
1979
1980 make_certificate(ipAddr, data_dir.ToStdString());
1981
1982 m_rest_server.StartServer(fs::path(data_dir.ToStdString()));
1983 StartMDNSService(g_hostname.ToStdString(), "opencpn-object-control-service",
1984 8000);
1985 }
1986 return TRUE;
1987}
1988
1989int MyApp::OnExit() {
1990 wxLogMessage(_T("opencpn::MyApp starting exit."));
1991 m_checker.OnExit();
1992 m_usb_watcher.Stop();
1993 // Send current nav status data to log file // pjotrc 2010.02.09
1994
1995 wxDateTime lognow = wxDateTime::Now();
1996 lognow.MakeGMT();
1997 wxString day = lognow.FormatISODate();
1998 wxString utc = lognow.FormatISOTime();
1999 wxString navmsg = _T("LOGBOOK: ");
2000 navmsg += day;
2001 navmsg += _T(" ");
2002 navmsg += utc;
2003 navmsg += _T(" UTC ");
2004
2005 if (bGPSValid) {
2006 wxString data;
2007 data.Printf(_T("OFF: Lat %10.5f Lon %10.5f "), gLat, gLon);
2008 navmsg += data;
2009
2010 wxString cog;
2011 if (std::isnan(gCog))
2012 cog.Printf(_T("COG ----- "));
2013 else
2014 cog.Printf(_T("COG %10.5f "), gCog);
2015
2016 wxString sog;
2017 if (std::isnan(gSog))
2018 sog.Printf(_T("SOG ----- "));
2019 else
2020 sog.Printf(_T("SOG %6.2f ") + getUsrSpeedUnit(), toUsrSpeed(gSog));
2021
2022 navmsg += cog;
2023 navmsg += sog;
2024
2025 } else {
2026 wxString data;
2027 data.Printf(_T("OFF: Lat %10.5f Lon %10.5f"), gLat, gLon);
2028 navmsg += data;
2029 }
2030 wxLogMessage(navmsg);
2031 g_loglast_time = lognow;
2032
2033 if (ptcmgr) delete ptcmgr;
2034
2035 for (Track *track : g_TrackList) {
2036 delete track;
2037 }
2038 g_TrackList.clear();
2039
2040 delete pConfig;
2041 delete pSelect;
2042 delete pSelectTC;
2043 delete pSelectAIS;
2044
2045 delete ps52plib;
2046 delete g_SencThreadManager;
2047
2048 if (g_pGroupArray) {
2049 for (unsigned int igroup = 0; igroup < g_pGroupArray->GetCount();
2050 igroup++) {
2051 delete g_pGroupArray->Item(igroup);
2052 }
2053
2054 g_pGroupArray->Clear();
2055 delete g_pGroupArray;
2056 }
2057
2058 wxLogMessage(_T("opencpn::MyApp exiting cleanly...\n"));
2059 wxLog::FlushActive();
2060
2061 g_Platform->CloseLogFile();
2062
2063 delete pInit_Chart_Dir;
2064
2065 for (Track *track : g_TrackList) {
2066 delete track;
2067 }
2068 g_TrackList.clear();
2069
2070 delete g_pRouteMan;
2071 delete pWayPointMan;
2072
2073 delete pMessageOnceArray;
2074
2075 DeInitializeUserColors();
2076
2077 delete pLayerList;
2078
2079 delete m_pRegistrarMan;
2080 CSVDeaccess(NULL);
2081
2082 delete g_StyleManager;
2083
2084#ifdef __WXMSW__
2085#ifdef USE_GLU_TESS
2086#ifdef USE_GLU_DLL
2087 if (s_glu_dll_ready) {
2088 FreeLibrary(s_hGLU_DLL);
2089 } // free the glu32.dll
2090#endif
2091#endif
2092#endif
2093
2094 // Restore any changed system colors
2095
2096#ifdef __WXMSW__
2097 void RestoreSystemColors(void);
2098 RestoreSystemColors();
2099#endif
2100
2101#ifdef __MSVC__LEAK
2102 DeInitAllocCheck();
2103#endif
2104
2105#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
2106 if (plocale_def_lang) delete plocale_def_lang;
2107#endif
2108
2109 FontMgr::Shutdown();
2110
2111 g_Platform->OnExit_2();
2113 delete g_Platform;
2114
2115 return TRUE;
2116}
2117
2118#ifdef LINUX_CRASHRPT
2119void MyApp::OnFatalException() { g_crashprint.Report(); }
2120#endif
2121
2122//----------------------------------------------------------------------------------------------------------
2123// Application-wide CPL Error handler
2124//----------------------------------------------------------------------------------------------------------
2125void MyCPLErrorHandler(CPLErr eErrClass, int nError, const char *pszErrorMsg)
2126
2127{
2128 char msg[256];
2129
2130 if (eErrClass == CE_Debug)
2131 snprintf(msg, 255, "CPL: %s", pszErrorMsg);
2132 else if (eErrClass == CE_Warning)
2133 snprintf(msg, 255, "CPL Warning %d: %s", nError, pszErrorMsg);
2134 else
2135 snprintf(msg, 255, "CPL ERROR %d: %s", nError, pszErrorMsg);
2136
2137 wxString str(msg, wxConvUTF8);
2138 wxLogMessage(str);
2139}
bool g_bresponsive
Flag to control adaptive UI scaling.
Definition ocpn_app.cpp:661
class About
Class AboutFrameImpl.
Global state for AIS decoder.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
Extends AboutFrame, providing implementation for various event handlers and additional methods.
The OpenCPN About dialog displaying information including version, authors, license,...
Definition about.h:52
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.
Represents an active track that is currently being recorded.
Definition track.h:226
Handles the AIS information GUI and sound alerts.
Dialog for managing CM93 chart offsets.
Definition cm93.h:547
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:151
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:233
Primary navigation console display for route and vessel tracking.
Definition concanv.h:127
const void Notify()
Notify all listeners, no data supplied.
void ScrubList()
Cleans up stale font entries after a locale change.
Definition FontMgr.cpp:565
static void SeedRandom()
Seed the random generator used by GetUUID().
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()
Dialog for displaying and editing waypoint properties.
Definition MarkInfo.h:212
Main application frame.
Definition ocpn_frame.h:136
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, std::function< void(ObservedEvt &ev)> action)
Initiate an object yet not listening.
Definition observable.h:255
bool LoadAllPlugIns(bool enabled_plugins, bool keep_orphans=false)
Update catalog with imported metadata and load all plugin library files.
A popup frame containing a detail slider for chart display.
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:70
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Definition route_point.h:50
Represents a navigational route in the navigation system.
Definition route.h:98
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
Definition route.h:202
wxString m_RouteNameString
User-assigned name for the route.
Definition route.h:246
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
Definition routeman.h:268
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Definition routeman.cpp:260
Dialog for displaying query results of S57 objects.
Manager for S57 chart SENC creation threads.
Definition tcmgr.h:86
Window for displaying chart thumbnails.
Definition thumbwin.h:56
Class TrackPropDlg.
Represents a track, which is a series of connected track points.
Definition track.h:111
Listen to hardware events and notifies SystemEvents when new devices are plugged in.
OpenGL chart rendering canvas.
Floating toolbar dialog for OpenCPN.
Definition toolbar.h:386
Handles crash reporting in wxWidgets applications.
Definition crashprint.h:35
Global variables reflecting command line options and arguments.
The local API has a server side handling commands and a client part issuing commands.
Enhanced logging interface on top of wx/log.h.
mDNS lookup wrappers.
Start/stop mdns service routines.
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:39
Class NotificationManager.
bool CheckDongleAccess(wxWindow *parent)
Runs checks and if required dialogs to make dongle accessible.
bool CheckSerialAccess(wxWindow *parent, const std::string device)
Run checks and possible dialogs to ensure device is accessible.
Access checks for comm devices and dongle.