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