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