30#include <malloc/malloc.h> 
   31#include <mach/vm_map.h> 
   36#include "androidUTIL.h" 
   56#include <sys/sysinfo.h> 
   65#include <wx/apptrait.h> 
   67#include <wx/filename.h> 
   68#include <wx/platinfo.h> 
   69#include <wx/stdpaths.h> 
   70#include <wx/textfile.h> 
   71#include <wx/tokenzr.h> 
   88static const char PATH_SEP = 
';';
 
   90static const char PATH_SEP = 
':';
 
   93bool AbstractPlatform::m_isBusy = 
false;
 
   95static const char* 
const DEFAULT_XDG_DATA_DIRS =
 
   96    "~/.local/share:/usr/local/share:/usr/share";
 
   98void appendOSDirSlash(wxString* pString);
 
  106static inline bool IsWindows() {
 
  107  return wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_WINDOWS;
 
  110static bool checkIfFlatpacked() {
 
  112  if (!wxGetEnv(
"FLATPAK_ID", &
id)) {
 
  115  return id == 
"org.opencpn.OpenCPN";
 
  120static wxString GetLinuxDataPath() {
 
  122  if (wxGetEnv(
"XDG_DATA_DIRS", &dirs)) {
 
  123    dirs = wxString(
"~/.local/share:") + dirs;
 
  125    dirs = DEFAULT_XDG_DATA_DIRS;
 
  128  wxStringTokenizer tokens(dirs, 
':');
 
  129  while (tokens.HasMoreTokens()) {
 
  130    wxString dir = tokens.GetNextToken();
 
  131    if (dir.EndsWith(
"/")) {
 
  132      dir = dir.SubString(0, dir.length() - 1);
 
  134    if (!dir.EndsWith(
"/opencpn/plugins")) {
 
  135      dir += 
"/opencpn/plugins";
 
  137    s += dir + (tokens.HasMoreTokens() ? 
";" : 
"");
 
  143  wxStringTokenizer tokens(paths, 
';');
 
  145  while (tokens.HasMoreTokens()) {
 
  146    wxFileName filename(tokens.GetNextToken());
 
  147    filename.Normalize();
 
  148    s += platform->NormalizePath(filename.GetFullPath());
 
  149    if (tokens.HasMoreTokens()) {
 
  157BasePlatform::BasePlatform() {
 
  159  m_isFlatpacked = checkIfFlatpacked();
 
  161  DetectOSDetail(m_osDetail);
 
  170BasePlatform::~BasePlatform() {
 
  172  delete wxLog::SetActiveTarget(
new wxLogStderr());
 
  179wxStandardPaths& AbstractPlatform::GetStdPaths() {
 
  181  return wxStandardPaths::Get();
 
  183  return *
dynamic_cast<wxStandardPaths*
>(
 
  184      &(wxTheApp->GetTraits())->GetStandardPaths());
 
  188wxString AbstractPlatform::NormalizePath(
const wxString& full_path) {
 
  192    wxString path(full_path);
 
  196      path = f.GetFullPath();
 
  202wxString& AbstractPlatform::GetHomeDir() {
 
  203  if (m_homeDir.IsEmpty()) {
 
  205    wxStandardPaths& std_path = GetStdPaths();
 
  210    std_path.SetInstallPrefix(wxString(PREFIX, wxConvUTF8));
 
  218    m_homeDir = std_path.GetUserConfigDir();
 
  222    m_homeDir = androidGetHomeDir();
 
  226      wxFileName path(GetExePath());
 
  227      m_homeDir = path.GetPath();
 
  231    appendOSDirSlash(&m_homeDir);
 
  232    m_homeDir.Append(
"opencpn");
 
  235    appendOSDirSlash(&m_homeDir);
 
  241wxString& AbstractPlatform::GetExePath() {
 
  242  if (m_exePath.IsEmpty()) {
 
  243    wxStandardPaths& std_path = GetStdPaths();
 
  244    m_exePath = std_path.GetExecutablePath();
 
  250wxString* AbstractPlatform::GetSharedDataDirPtr() {
 
  251  if (m_SData_Dir.IsEmpty()) GetSharedDataDir();
 
  257  return &m_PrivateDataDir;
 
 
  260wxString& AbstractPlatform::GetSharedDataDir() {
 
  261  if (m_SData_Dir.IsEmpty()) {
 
  272    wxStandardPaths& std_path = GetStdPaths();
 
  273    m_SData_Dir = std_path.GetDataDir();
 
  274    appendOSDirSlash(&m_SData_Dir);
 
  277    m_SData_Dir = androidGetSharedDir();
 
  280    if (g_bportable) m_SData_Dir = GetHomeDir();
 
  289  lic = androidGetSupplementalLicense();
 
 
  295  static const wxString sep = wxFileName::GetPathSeparator();
 
  298  wxLogMessage(
"PlugInManager: Using data dirs from: " + datadirs);
 
  299  wxStringTokenizer dirs(datadirs, 
";");
 
  300  while (dirs.HasMoreTokens()) {
 
  301    wxString dir = dirs.GetNextToken();
 
  302    wxFileName tryDirName(dir);
 
  304    if (!tryDir.Open(tryDirName.GetFullPath())) 
continue;
 
  306    bool more = tryDir.GetFirst(&next);
 
  308      if (next == plugin_name) {
 
  309        next = next.Prepend(tryDirName.GetFullPath() + sep);
 
  310        wxLogMessage(
"PlugInManager: using data dir: %s", next);
 
  313      more = tryDir.GetNext(&next);
 
  317  wxLogMessage(
"Warning: no data directory found, using \"\"");
 
 
  322  if (!m_PrivateDataDir.IsEmpty() && g_configdir.empty())
 
  323    return m_PrivateDataDir;
 
  324  if (!g_configdir.empty()) {
 
  325    wxString path = g_configdir;
 
  326    if (path.Last() == wxFileName::GetPathSeparator()) path.RemoveLast();
 
  327    m_default_private_datadir = path;
 
  328    return m_default_private_datadir;  
 
 
  335  if (m_PrivateDataDir.IsEmpty()) {
 
  337    wxStandardPaths& std_path = GetStdPaths();
 
  343    std::string config_home;
 
  344    if (getenv(
"XDG_CONFIG_HOME")) {
 
  345      config_home = getenv(
"XDG_CONFIG_HOME");
 
  347      config_home = getenv(
"HOME");
 
  348      config_home += 
"/.var/app/org.opencpn.OpenCPN/config";
 
  350    m_PrivateDataDir = config_home + 
"/opencpn";
 
  352#elif defined __WXOSX__ 
  354        std_path.GetUserConfigDir();  
 
  355    appendOSDirSlash(&m_PrivateDataDir);
 
  356    m_PrivateDataDir.Append(
"opencpn");
 
  358    m_PrivateDataDir = std_path.GetUserDataDir();  
 
  361    if (g_bportable) m_PrivateDataDir = GetHomeDir();
 
  362    if (m_PrivateDataDir.Last() == wxFileName::GetPathSeparator())
 
  363      m_PrivateDataDir.RemoveLast();
 
  366    m_PrivateDataDir = androidGetPrivateDir();
 
  369  return m_PrivateDataDir;
 
 
  374    wxLogMessage(
"winPluginDir: Using value from ini file.");
 
  376    if (!fn.DirExists()) {
 
  377      wxLogWarning(
"Plugin dir %s does not exist",
 
  378                   fn.GetFullPath().mb_str().data());
 
  381    return fn.GetFullPath();
 
  383  wxString winPluginDir;
 
  386    winPluginDir = (GetHomeDir() + 
"plugins");
 
  388      wxLogMessage(
"Using portable plugin dir: %s", winPluginDir);
 
  393  bool ok = wxGetEnv(
"LOCALAPPDATA", &winPluginDir);
 
  395    wxLogMessage(
"winPluginDir: Cannot lookup LOCALAPPDATA");
 
  397    std::string path(wxGetHomeDir().ToStdString());
 
  398    path += 
"\\AppData\\Local";
 
  400      winPluginDir = wxString(path.c_str());
 
  401      wxLogMessage(
"winPluginDir: using %s", winPluginDir.mb_str().data());
 
  407    ok = wxGetEnv(
"APPDATA", &winPluginDir);
 
  411    wxLogMessage(
"winPluginDir: Cannot lookup APPDATA");
 
  412    std::string path(wxGetHomeDir().ToStdString());
 
  413    path += 
"\\AppData\\Roaming";
 
  415      winPluginDir = wxString(path.c_str());
 
  417      wxLogMessage(
"winPluginDir: using %s", winPluginDir.mb_str().data());
 
  422    winPluginDir = GetHomeDir();
 
  424  wxFileName path(winPluginDir);
 
  426  winPluginDir = path.GetFullPath() + 
"\\opencpn\\plugins";
 
  427  wxLogMessage(
"Using private plugin dir: %s", winPluginDir);
 
 
  432  if (m_PluginsDir.IsEmpty()) {
 
  433    wxStandardPaths& std_path = GetStdPaths();
 
  436    m_PluginsDir = std_path.GetPluginsDir();  
 
  439    m_PluginsDir += 
"\\plugins";  
 
  442      m_PluginsDir = GetHomeDir();
 
  443      m_PluginsDir += 
"plugins";
 
  448    wxFileName fdir = wxFileName::DirName(std_path.GetUserConfigDir());
 
  449    fdir.RemoveLastDir();
 
  450    m_PluginsDir = fdir.GetPath();
 
 
  456wxString* AbstractPlatform::GetPluginDirPtr() {
 
  458  return &m_PluginsDir;
 
  461bool AbstractPlatform::isPlatformCapable(
int flag) {
 
  465  if (flag == PLATFORM_CAP_PLUGINS) {
 
  467    wxString tsdk(android_plat_spc.msdk);
 
  468    if (tsdk.ToLong(&platver)) {
 
  469      if (platver >= 11) 
return true;
 
  471  } 
else if (flag == PLATFORM_CAP_FASTPAN) {
 
  473    wxString tsdk(android_plat_spc.msdk);
 
  474    if (tsdk.ToLong(&platver)) {
 
  475      if (platver >= 14) 
return true;
 
  483void appendOSDirSlash(wxString* pString) {
 
  484  wxChar sep = wxFileName::GetPathSeparator();
 
  485  if (pString->Last() != sep) pString->Append(sep);
 
  488wxString AbstractPlatform::GetWritableDocumentsDir() {
 
  492  dir = androidGetExtStorageDir();  
 
  494  wxStandardPaths& std_path = GetStdPaths();
 
  495  dir = std_path.GetDocumentsDir();
 
  500bool AbstractPlatform::DetectOSDetail(
OCPN_OSDetail* detail) {
 
  501  if (!detail) 
return false;
 
  504  detail->osd_name = std::string(PKG_TARGET);
 
  505  detail->osd_version = std::string(PKG_TARGET_VERSION);
 
  509  if (wxFileExists(
"/etc/os-release")) {
 
  510    wxTextFile release_file(
"/etc/os-release");
 
  511    if (release_file.Open()) {
 
  513      for (wxString str = release_file.GetFirstLine(); !release_file.Eof();
 
  514           str = release_file.GetNextLine()) {
 
  515        if (str.StartsWith(
"NAME")) {
 
  516          val = str.AfterFirst(
'=').Mid(1);
 
  517          val = val.Mid(0, val.Length() - 1);
 
  518          if (val.Length()) detail->osd_name = std::string(val.mb_str());
 
  519        } 
else if (str.StartsWith(
"VERSION_ID")) {
 
  520          val = str.AfterFirst(
'=').Mid(1);
 
  521          val = val.Mid(0, val.Length() - 1);
 
  522          if (val.Length()) detail->osd_version = std::string(val.mb_str());
 
  523        } 
else if (str.StartsWith(
"ID=")) {
 
  524          val = str.AfterFirst(
'=');
 
  525          if (val.Length()) detail->osd_ID = 
ocpn::split(val.mb_str(), 
" ")[0];
 
  526        } 
else if (str.StartsWith(
"ID_LIKE")) {
 
  527          if (val.StartsWith(
'"')) {
 
  528            val = str.AfterFirst(
'=').Mid(1);
 
  529            val = val.Mid(0, val.Length() - 1);
 
  531            val = str.AfterFirst(
'=');
 
  535            detail->osd_names_like = 
ocpn::split(val.mb_str(), 
" ");
 
  540      release_file.Close();
 
  542    if (detail->osd_name == 
"Linux Mint") {
 
  543      if (wxFileExists(
"/etc/upstream-release/lsb-release")) {
 
  544        wxTextFile upstream_release_file(
"/etc/upstream-release/lsb-release");
 
  545        if (upstream_release_file.Open()) {
 
  547          for (wxString str = upstream_release_file.GetFirstLine();
 
  548               !upstream_release_file.Eof();
 
  549               str = upstream_release_file.GetNextLine()) {
 
  550            if (str.StartsWith(
"DISTRIB_RELEASE")) {
 
  551              val = str.AfterFirst(
'=').Mid(0);
 
  552              val = val.Mid(0, val.Length());
 
  553              if (val.Length()) detail->osd_version = std::string(val.mb_str());
 
  556          upstream_release_file.Close();
 
  564  detail->osd_arch = std::string(
"x86_64");
 
  567  wxPlatformInfo platformInfo = wxPlatformInfo::Get();
 
  568  wxArchitecture arch = platformInfo.GetArchitecture();
 
  569  if (arch == wxARCH_32) detail->osd_arch = std::string(
"i386");
 
  575  detail->osd_arch = std::string(
"arm64");
 
  577  detail->osd_arch = std::string(
"armhf");
 
  582  detail->osd_arch = std::string(
"arm64");
 
  583  if (arch == wxARCH_32) detail->osd_arch = std::string(
"armhf");
 
  587  if (IsAppleSilicon() == 1) {
 
  588    if (ProcessIsTranslated() != 1) {
 
  589      detail->osd_arch = std::string(
"arm64");
 
  591      detail->osd_arch = std::string(
"x86_64");
 
  594    detail->osd_arch = std::string(
"x86_64");
 
  601wxString& AbstractPlatform::GetConfigFileName() {
 
  602  if (m_config_file_name.IsEmpty()) {
 
  604    wxStandardPaths& std_path = GetStdPaths();
 
  607    m_config_file_name = 
"opencpn.ini";
 
  608    m_config_file_name.Prepend(GetHomeDir());
 
  610#elif defined __WXOSX__ 
  612        std_path.GetUserConfigDir();  
 
  613    appendOSDirSlash(&m_config_file_name);
 
  614    m_config_file_name.Append(
"opencpn");
 
  615    appendOSDirSlash(&m_config_file_name);
 
  616    m_config_file_name.Append(
"opencpn.ini");
 
  619    m_config_file_name.Append(
"/opencpn.conf");
 
  622    m_config_file_name = std_path.GetUserDataDir();  
 
  623    appendOSDirSlash(&m_config_file_name);
 
  624    m_config_file_name.Append(
"opencpn.conf");
 
  628      m_config_file_name = GetHomeDir();
 
  630      m_config_file_name += 
"opencpn.ini";
 
  631#elif defined __WXOSX__ 
  632      m_config_file_name += 
"opencpn.ini";
 
  634      m_config_file_name += 
"opencpn.conf";
 
  639    m_config_file_name = androidGetPrivateDir();
 
  640    appendOSDirSlash(&m_config_file_name);
 
  641    m_config_file_name += 
"opencpn.conf";
 
  643    if (!g_configdir.empty()) {
 
  644      m_config_file_name = g_configdir;
 
  645      m_config_file_name.Append(
"/opencpn.conf");
 
  648  return m_config_file_name;
 
  651bool BasePlatform::InitializeLogFile() {
 
  654  appendOSDirSlash(&mlog_file);
 
  658  wxFileName LibPref(mlog_file);  
 
  659  LibPref.RemoveLastDir();        
 
  660  LibPref.RemoveLastDir();        
 
  662  mlog_file = LibPref.GetFullPath();
 
  663  appendOSDirSlash(&mlog_file);
 
  665  mlog_file.Append(
"Logs/");  
 
  671  wxFileName wxHomeFiledir(GetHomeDir());
 
  672  if (
true != wxHomeFiledir.DirExists(wxHomeFiledir.GetPath()))
 
  673    if (!wxHomeFiledir.Mkdir(wxHomeFiledir.GetPath())) {
 
  674      wxASSERT_MSG(
false, 
"Cannot create opencpn home directory");
 
  679  wxFileName wxLogFiledir(mlog_file);
 
  680  if (
true != wxLogFiledir.DirExists(wxLogFiledir.GetPath())) {
 
  681    if (!wxLogFiledir.Mkdir(wxLogFiledir.GetPath())) {
 
  682      wxASSERT_MSG(
false, 
"Cannot create opencpn log directory");
 
  687  mlog_file.Append(
"opencpn.log");
 
  688  wxString logit = mlog_file;
 
  691  wxCharBuffer abuf = mlog_file.ToUTF8();
 
  692  qDebug() << 
"logfile " << abuf.data();
 
  696  if (::wxFileExists(mlog_file)) {
 
  697    if (wxFileName::GetSize(mlog_file) > 1000000) {
 
  698      wxString oldlog = mlog_file;
 
  699      oldlog.Append(
".log");
 
  702      large_log_message = (
"Old log will be moved to opencpn.log.log");
 
  703      ::wxRenameFile(mlog_file, oldlog);
 
  707  if (::wxFileExists(mlog_file)) {
 
  710    ::wxRemoveFile(mlog_file);
 
  714  if (wxLog::GetLogLevel() > wxLOG_User) wxLog::SetLogLevel(wxLOG_Info);
 
  716  auto logger = 
new OcpnLog(mlog_file.mb_str());
 
  720  m_old_logger = wxLog::SetActiveTarget(logger);
 
  725void AbstractPlatform::CloseLogFile() {
 
  727    delete wxLog::SetActiveTarget(m_old_logger);
 
  728    m_old_logger = 
nullptr;
 
  734    wxString sep = wxFileName::GetPathSeparator();
 
  739  if (m_pluginDataPath != 
"") {
 
  740    return m_pluginDataPath;
 
  747  auto const osSystemId = wxPlatformInfo::Get().GetOperatingSystemId();
 
  748  if (isFlatpacked()) {
 
  749    dirs = 
"~/.var/app/org.opencpn.OpenCPN/data/opencpn/plugins";
 
  750  } 
else if (osSystemId & wxOS_UNIX_LINUX) {
 
  751    dirs = GetLinuxDataPath();
 
  752  } 
else if (osSystemId & wxOS_WINDOWS) {
 
  754  } 
else if (osSystemId & wxOS_MAC) {
 
  755    dirs = 
"/Applications/OpenCPN.app/Contents/SharedSupport/plugins;";
 
  757        "~/Library/Application Support/OpenCPN/Contents/SharedSupport/plugins";
 
  761  m_pluginDataPath = ExpandPaths(dirs, 
this);
 
  762  if (m_pluginDataPath != 
"") {
 
  763    m_pluginDataPath += 
";";
 
  766  if (m_pluginDataPath.EndsWith(wxFileName::GetPathSeparator())) {
 
  767    m_pluginDataPath.RemoveLast();
 
  769  wxLogMessage(
"Using plugin data path: %s", m_pluginDataPath.mb_str().data());
 
  770  return m_pluginDataPath;
 
 
  774void AbstractPlatform::ShowBusySpinner() {
 
  776    androidShowBusyIcon();
 
  781void AbstractPlatform::ShowBusySpinner() {
 
  783    ::wxBeginBusyCursor();
 
  790void AbstractPlatform::HideBusySpinner() {
 
  792    androidHideBusyIcon();
 
  797void AbstractPlatform::HideBusySpinner() {
 
  807#if defined(__ANDROID__) 
  808wxSize BasePlatform::getDisplaySize() { 
return getAndroidDisplayDimensions(); }
 
  811wxSize BasePlatform::getDisplaySize() { 
return wxSize(0, 0); }
 
  815double BasePlatform::GetDisplaySizeMM() {
 
  816  if (m_displaySizeMMOverride.size() > 0 && m_displaySizeMMOverride[0] > 0) {
 
  817    return m_displaySizeMMOverride[0];
 
  822  ret = GetAndroidDisplaySize();
 
  825  wxLogDebug(
"Detected display size (horizontal): %d mm", (
int)ret);
 
  829#if defined(__ANDROID__) 
  830double BasePlatform::GetDisplayDPmm() { 
return getAndroidDPmm(); }
 
  833double BasePlatform::GetDisplayDPmm() {
 
  834  if (
dynamic_cast<wxApp*
>(wxAppConsole::GetInstance())) {
 
  835    double r = getDisplaySize().x;  
 
  836    return r / GetDisplaySizeMM();
 
  847  if (win) rv = (double)(win->ToDIP(100)) / 100.;
 
 
  852unsigned int AbstractPlatform::GetSelectRadiusPix() {
 
  853  return GetDisplayDPmm() *
 
  854         (g_btouch ? g_selection_radius_touch_mm : g_selection_radius_mm);
 
  861const GUID GUID_CLASS_MONITOR = {0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08,
 
  862                                 0x00,       0x2b,   0xe1,   0x03, 0x18};
 
  865bool GetMonitorSizeFromEDID(
const HKEY hDevRegKey, 
int* WidthMm,
 
  867  DWORD dwType, AcutalValueNameLength = NAME_SIZE;
 
  868  TCHAR valueName[NAME_SIZE];
 
  871  DWORD edidsize = 
sizeof(EDIDdata);
 
  873  for (LONG i = 0, retValue = ERROR_SUCCESS; retValue != ERROR_NO_MORE_ITEMS;
 
  875    retValue = RegEnumValue(hDevRegKey, i, &valueName[0],
 
  876                            &AcutalValueNameLength, NULL, &dwType,
 
  880    if (retValue != ERROR_SUCCESS || 0 != _tcscmp(valueName, L
"EDID")) 
continue;
 
  882    *WidthMm = ((EDIDdata[68] & 0xF0) << 4) + EDIDdata[66];
 
  883    *HeightMm = ((EDIDdata[68] & 0x0F) << 8) + EDIDdata[67];
 
  891bool GetSizeForDevID(wxString& TargetDevID, 
int* WidthMm, 
int* HeightMm) {
 
  893      SetupDiGetClassDevsEx(&GUID_CLASS_MONITOR,  
 
  901  if (NULL == devInfo) 
return false;
 
  905  for (ULONG i = 0; ERROR_NO_MORE_ITEMS != GetLastError(); ++i) {
 
  906    SP_DEVINFO_DATA devInfoData;
 
  907    memset(&devInfoData, 0, 
sizeof(devInfoData));
 
  908    devInfoData.cbSize = 
sizeof(devInfoData);
 
  910    if (SetupDiEnumDeviceInfo(devInfo, i, &devInfoData)) {
 
  911      wchar_t Instance[80];
 
  912      SetupDiGetDeviceInstanceId(devInfo, &devInfoData, Instance, MAX_PATH,
 
  914      wxString instance(Instance);
 
  915      if (instance.Upper().Find(TargetDevID.Upper()) == wxNOT_FOUND) 
continue;
 
  917      HKEY hDevRegKey = SetupDiOpenDevRegKey(
 
  918          devInfo, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
 
  920      if (!hDevRegKey || (hDevRegKey == INVALID_HANDLE_VALUE)) 
continue;
 
  922      bRes = GetMonitorSizeFromEDID(hDevRegKey, WidthMm, HeightMm);
 
  924      RegCloseKey(hDevRegKey);
 
  927  SetupDiDestroyDeviceInfoList(devInfo);
 
  931bool AbstractPlatform::GetWindowsMonitorSize(
int* width, 
int* height) {
 
  932  bool bFoundDevice = 
true;
 
  934  if (m_monitorWidth < 10) {
 
  944    bFoundDevice = 
false;
 
  945    while (EnumDisplayDevices(0, dev, &dd, 0) && !bFoundDevice) {
 
  946      DISPLAY_DEVICE ddMon;
 
  947      ZeroMemory(&ddMon, 
sizeof(ddMon));
 
  948      ddMon.cb = 
sizeof(ddMon);
 
  951      while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0) &&
 
  953        if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE &&
 
  954            !(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) {
 
  955          DeviceID = wxString(ddMon.DeviceID, wxConvUTF8);
 
  956          DeviceID = DeviceID.Mid(8);
 
  957          DeviceID = DeviceID.Mid(0, DeviceID.Find(
'\\'));
 
  959          bFoundDevice = GetSizeForDevID(DeviceID, &WidthMm, &HeightMm);
 
  963        ZeroMemory(&ddMon, 
sizeof(ddMon));
 
  964        ddMon.cb = 
sizeof(ddMon);
 
  967      ZeroMemory(&dd, 
sizeof(dd));
 
  971    m_monitorWidth = WidthMm;
 
  972    m_monitorHeight = HeightMm;
 
  975  if (width) *width = m_monitorWidth;
 
  976  if (height) *height = m_monitorHeight;
 
  984  double size = w->GetCharHeight() * (IsWindows() ? 1.3 : 1.0);
 
  985#if wxCHECK_VERSION(3, 1, 2) 
  988  size *= 
static_cast<double>(w->ToDIP(100)) / 100.;
 
  992    double pixel_per_mm = wxGetDisplaySize().x / GetDisplaySizeMM();
 
  993    size = std::max(size, 7.0 * pixel_per_mm);
 
  995  return std::round(size);
 
 
 1000  return androidGetMemoryStatus(mem_total, mem_used);
 
 1003#if defined(__linux__) 
 1007    struct sysinfo sys_info;
 
 1008    if (sysinfo(&sys_info) != -1)
 
 1009      *mem_total = ((uint64_t)sys_info.totalram * sys_info.mem_unit) / 1024;
 
 1023    FILE* file = fopen(
"/proc/self/statm", 
"r");
 
 1025      if (fscanf(file, 
"%d", mem_used) != 1) {
 
 1026        wxLogWarning(
"Cannot parse /proc/self/statm (!)");
 
 1039  PROCESS_MEMORY_COUNTERS pmc;
 
 1041  unsigned long processID = wxGetProcessId();
 
 1044    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
 
 1047    if (hProcess && GetProcessMemoryInfo(hProcess, &pmc, 
sizeof(pmc))) {
 
 1065      *mem_used = pmc.WorkingSetSize / 1024;
 
 1068    CloseHandle(hProcess);
 
 1072    MEMORYSTATUSEX statex;
 
 1074    statex.dwLength = 
sizeof(statex);
 
 1076    GlobalMemoryStatusEx(&statex);
 
 1094    *mem_total = statex.ullTotalPhys / 1024;
 
 1101  if (g_tick != g_lastMemTick) {
 
 1102    malloc_zone_pressure_relief(NULL, 0);
 
 1105    int blocksInUse = 0;
 
 1106    int sizeAllocated = 0;
 
 1108    malloc_statistics_t stats;
 
 1109    stats.blocks_in_use = 0;
 
 1110    stats.size_in_use = 0;
 
 1111    stats.max_size_in_use = 0;
 
 1112    stats.size_allocated = 0;
 
 1113    malloc_zone_statistics(NULL, &stats);
 
 1114    bytesInUse += stats.size_in_use;
 
 1115    blocksInUse += stats.blocks_in_use;
 
 1116    sizeAllocated += stats.size_allocated;
 
 1118    g_memUsed = sizeAllocated >> 10;
 
 1121    g_lastMemTick = g_tick;
 
 1124  if (mem_used) *mem_used = g_memUsed;
 
 1127    FILE* fpIn = popen(
"sysctl -n hw.memsize", 
"r");
 
 1129      double pagesUsed = 0.0, totalPages = 0.0;
 
 1131      if (fgets(buf, 
sizeof(buf), fpIn) != NULL) {
 
 1132        *mem_total = atol(buf) >> 10;
 
 1140  if (mem_used) *mem_used = 0;
 
 1141  if (mem_total) *mem_total = 0;
 
 
Customized logger class appending to a file providing:
Global variables reflecting command line options and arguments.
wxString g_winPluginDir
Base plugin directory on Windows.
Global variables stored in configuration file.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Enhanced logging interface on top of wx/log.h.
MacOS hardware probing functions.
std::vector< std::string > split(const char *token_string, const std::string &delimiter)
Return vector of items in s separated by delimiter.
bool exists(const std::string &name)
PlugIn Object Definition/API.
Miscellaneous utilities, many of which string related.