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