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