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