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