annotate system/System.cpp @ 1818:c5ee0746bdef background-mode

Determine whether a dark background is indicated
author Chris Cannam
date Fri, 17 Jan 2020 21:36:07 +0000
parents 85903b0e9b42
children 4eda6ba5b5d8
rev   line source
Chris@223 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@223 2
Chris@223 3 /*
Chris@1356 4 Sonic Visualiser
Chris@1356 5 An audio file viewer and annotation editor.
Chris@1356 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1475 7 This file copyright 2006-2018 Chris Cannam and QMUL.
Chris@223 8
Chris@1356 9 This program is free software; you can redistribute it and/or
Chris@1356 10 modify it under the terms of the GNU General Public License as
Chris@1356 11 published by the Free Software Foundation; either version 2 of the
Chris@1356 12 License, or (at your option) any later version. See the file
Chris@1356 13 COPYING included with this distribution for more information.
Chris@223 14 */
Chris@223 15
Chris@223 16 #include "System.h"
Chris@223 17
Chris@223 18 #include <QStringList>
Chris@223 19 #include <QString>
Chris@223 20
Chris@223 21 #include <stdint.h>
Chris@223 22
Chris@223 23 #ifndef _WIN32
Chris@223 24 #include <signal.h>
Chris@223 25 #include <sys/statvfs.h>
Chris@608 26 #include <locale.h>
Chris@608 27 #include <unistd.h>
Chris@223 28 #endif
Chris@223 29
Chris@1818 30 #ifdef _MSC_VER
Chris@1818 31 #include <winrt/Windows.UI.ViewManagement.h>
Chris@1818 32 #endif
Chris@1818 33
Chris@223 34 #ifdef __APPLE__
Chris@223 35 #include <sys/param.h>
Chris@223 36 #include <sys/sysctl.h>
Chris@223 37 #endif
Chris@223 38
Chris@405 39 #include <limits.h>
Chris@405 40 #include <cstdlib>
Chris@405 41
Chris@223 42 #include <iostream>
Chris@223 43
Chris@255 44 #ifdef __APPLE__
Chris@255 45 extern "C" {
Chris@1356 46 void *
Chris@1356 47 rpl_realloc (void *p, size_t n)
Chris@255 48 {
Chris@1356 49 p = realloc(p, n);
Chris@1356 50 if (p == 0 && n == 0)
Chris@1356 51 {
Chris@1356 52 p = malloc(0);
Chris@1356 53 }
Chris@1356 54 return p;
Chris@255 55 }
Chris@255 56 }
Chris@255 57 #endif
Chris@255 58
Chris@223 59 #ifdef _WIN32
Chris@223 60
Chris@223 61 extern "C" {
Chris@223 62
Chris@1218 63 #ifdef _MSC_VER
Chris@1356 64 void usleep(unsigned long usec)
Chris@1356 65 {
Chris@1356 66 ::Sleep(usec / 1000);
Chris@1356 67 }
Chris@1218 68 #endif
Chris@223 69
Chris@1475 70 int gettimeofday(struct timeval *tv, void * /* tz */)
Chris@1356 71 {
Chris@1356 72 union {
Chris@1356 73 long long ns100;
Chris@1356 74 FILETIME ft;
Chris@1356 75 } now;
Chris@223 76
Chris@1356 77 ::GetSystemTimeAsFileTime(&now.ft);
Chris@1356 78 tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL);
Chris@1356 79 tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL);
Chris@1356 80 return 0;
Chris@1356 81 }
Chris@223 82
Chris@223 83 }
Chris@223 84
Chris@223 85 #endif
Chris@223 86
Chris@223 87 ProcessStatus
Chris@223 88 GetProcessStatus(int pid)
Chris@223 89 {
Chris@223 90 #ifdef _WIN32
Chris@223 91 HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
Chris@223 92 if (!handle) {
Chris@223 93 return ProcessNotRunning;
Chris@223 94 } else {
Chris@223 95 CloseHandle(handle);
Chris@223 96 return ProcessRunning;
Chris@223 97 }
Chris@223 98 #else
Chris@223 99 if (kill(getpid(), 0) == 0) {
Chris@223 100 if (kill(pid, 0) == 0) {
Chris@223 101 return ProcessRunning;
Chris@223 102 } else {
Chris@223 103 return ProcessNotRunning;
Chris@223 104 }
Chris@223 105 } else {
Chris@223 106 return UnknownProcessStatus;
Chris@223 107 }
Chris@223 108 #endif
Chris@223 109 }
Chris@223 110
Chris@223 111 #ifdef _WIN32
Chris@223 112 /* MEMORYSTATUSEX is missing from older Windows headers, so define a
Chris@223 113 local replacement. This trick from MinGW source code. Ugh */
Chris@223 114 typedef struct
Chris@223 115 {
Chris@223 116 DWORD dwLength;
Chris@223 117 DWORD dwMemoryLoad;
Chris@223 118 DWORDLONG ullTotalPhys;
Chris@223 119 DWORDLONG ullAvailPhys;
Chris@223 120 DWORDLONG ullTotalPageFile;
Chris@223 121 DWORDLONG ullAvailPageFile;
Chris@223 122 DWORDLONG ullTotalVirtual;
Chris@223 123 DWORDLONG ullAvailVirtual;
Chris@223 124 DWORDLONG ullAvailExtendedVirtual;
Chris@223 125 } lMEMORYSTATUSEX;
Chris@1218 126 typedef BOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
Chris@223 127 #endif
Chris@223 128
Chris@223 129 void
Chris@1038 130 GetRealMemoryMBAvailable(ssize_t &available, ssize_t &total)
Chris@223 131 {
Chris@223 132 available = -1;
Chris@223 133 total = -1;
Chris@223 134
Chris@223 135 #ifdef _WIN32
Chris@223 136
Chris@223 137 static bool checked = false;
Chris@223 138 static bool exFound = false;
Chris@223 139 static PFN_MS_EX ex;
Chris@223 140
Chris@223 141 if (!checked) {
Chris@223 142
Chris@223 143 HMODULE h = GetModuleHandleA("kernel32.dll");
Chris@223 144
Chris@223 145 if (h) {
Chris@223 146 if ((ex = (PFN_MS_EX)GetProcAddress(h, "GlobalMemoryStatusEx"))) {
Chris@223 147 exFound = true;
Chris@223 148 }
Chris@223 149 }
Chris@223 150
Chris@223 151 checked = true;
Chris@223 152 }
Chris@223 153
Chris@223 154 DWORDLONG wavail = 0;
Chris@223 155 DWORDLONG wtotal = 0;
Chris@223 156
Chris@223 157 if (exFound) {
Chris@223 158
Chris@223 159 lMEMORYSTATUSEX lms;
Chris@1356 160 lms.dwLength = sizeof(lms);
Chris@1356 161 if (!ex(&lms)) {
Chris@843 162 cerr << "WARNING: GlobalMemoryStatusEx failed: error code "
Chris@1356 163 << GetLastError() << endl;
Chris@223 164 return;
Chris@223 165 }
Chris@223 166 wavail = lms.ullAvailPhys;
Chris@223 167 wtotal = lms.ullTotalPhys;
Chris@223 168
Chris@223 169 } else {
Chris@223 170
Chris@223 171 /* Fall back to GlobalMemoryStatus which is always available.
Chris@223 172 but returns wrong results for physical memory > 4GB */
Chris@223 173
Chris@1356 174 MEMORYSTATUS ms;
Chris@1356 175 GlobalMemoryStatus(&ms);
Chris@1356 176 wavail = ms.dwAvailPhys;
Chris@223 177 wtotal = ms.dwTotalPhys;
Chris@223 178 }
Chris@223 179
Chris@223 180 DWORDLONG size = wavail / 1048576;
Chris@223 181 if (size > INT_MAX) size = INT_MAX;
Chris@1038 182 available = ssize_t(size);
Chris@223 183
Chris@223 184 size = wtotal / 1048576;
Chris@223 185 if (size > INT_MAX) size = INT_MAX;
Chris@1038 186 total = ssize_t(size);
Chris@223 187
Chris@223 188 return;
Chris@223 189
Chris@223 190 #else
Chris@223 191 #ifdef __APPLE__
Chris@223 192
Chris@1779 193 unsigned int val32;
Chris@1779 194 int64_t val64;
Chris@223 195 int mib[2];
Chris@223 196 size_t size_sys;
Chris@223 197
Chris@223 198 mib[0] = CTL_HW;
Chris@223 199
Chris@1779 200 mib[1] = HW_MEMSIZE;
Chris@1779 201 size_sys = sizeof(val64);
Chris@1779 202 sysctl(mib, 2, &val64, &size_sys, NULL, 0);
Chris@1779 203 if (val64) total = val64 / 1048576;
Chris@223 204
Chris@223 205 mib[1] = HW_USERMEM;
Chris@1779 206 size_sys = sizeof(val32);
Chris@1779 207 sysctl(mib, 2, &val32, &size_sys, NULL, 0);
Chris@1779 208 if (val32) available = val32 / 1048576;
Chris@1779 209
Chris@1779 210 // The newer memsize sysctl returns a 64-bit value, but usermem is
Chris@1779 211 // an old 32-bit value that doesn't seem to have an updated
Chris@1779 212 // alternative (?) - so it can't return more than 2G. In practice
Chris@1779 213 // it seems to return values far lower than that, even where more
Chris@1779 214 // than 2G of real memory is free. So we can't actually tell when
Chris@1779 215 // we're getting low on memory at all. Most of the time I think we
Chris@1779 216 // just need to use an arbitrary value like this one.
Chris@1779 217 if (available < total/4) {
Chris@1779 218 available = total/4;
Chris@1779 219 }
Chris@223 220
Chris@223 221 return;
Chris@223 222
Chris@223 223 #else
Chris@223 224
Chris@223 225 FILE *meminfo = fopen("/proc/meminfo", "r");
Chris@223 226 if (!meminfo) return;
Chris@223 227
Chris@223 228 char buf[256];
Chris@223 229 while (!feof(meminfo)) {
Chris@1363 230 if (!fgets(buf, 256, meminfo)) {
Chris@1424 231 fclose(meminfo);
Chris@1363 232 return;
Chris@1363 233 }
Chris@223 234 bool isMemFree = (strncmp(buf, "MemFree:", 8) == 0);
Chris@223 235 bool isMemTotal = (!isMemFree && (strncmp(buf, "MemTotal:", 9) == 0));
Chris@223 236 if (isMemFree || isMemTotal) {
Chris@223 237 QString line = QString(buf).trimmed();
Chris@223 238 QStringList elements = line.split(' ', QString::SkipEmptyParts);
Chris@223 239 QString unit = "kB";
Chris@223 240 if (elements.size() > 2) unit = elements[2];
Chris@223 241 int size = elements[1].toInt();
Chris@843 242 // cerr << "have size \"" << size << "\", unit \""
Chris@843 243 // << unit << "\"" << endl;
Chris@223 244 if (unit.toLower() == "gb") size = size * 1024;
Chris@223 245 else if (unit.toLower() == "mb") size = size;
Chris@223 246 else if (unit.toLower() == "kb") size = size / 1024;
Chris@223 247 else size = size / 1048576;
Chris@223 248
Chris@223 249 if (isMemFree) available = size;
Chris@223 250 else total = size;
Chris@223 251 }
Chris@223 252 if (available != -1 && total != -1) {
Chris@223 253 fclose(meminfo);
Chris@223 254 return;
Chris@223 255 }
Chris@223 256 }
Chris@223 257 fclose(meminfo);
Chris@223 258
Chris@223 259 return;
Chris@223 260
Chris@223 261 #endif
Chris@223 262 #endif
Chris@223 263 }
Chris@223 264
Chris@1038 265 ssize_t
Chris@223 266 GetDiscSpaceMBAvailable(const char *path)
Chris@223 267 {
Chris@223 268 #ifdef _WIN32
Chris@223 269 ULARGE_INTEGER available, total, totalFree;
Chris@223 270 if (GetDiskFreeSpaceExA(path, &available, &total, &totalFree)) {
Chris@1356 271 __int64 a = available.QuadPart;
Chris@223 272 a /= 1048576;
Chris@223 273 if (a > INT_MAX) a = INT_MAX;
Chris@1038 274 return ssize_t(a);
Chris@223 275 } else {
Chris@843 276 cerr << "WARNING: GetDiskFreeSpaceEx failed: error code "
Chris@1356 277 << GetLastError() << endl;
Chris@223 278 return -1;
Chris@223 279 }
Chris@223 280 #else
Chris@223 281 struct statvfs buf;
Chris@223 282 if (!statvfs(path, &buf)) {
Chris@223 283 // do the multiplies and divides in this order to reduce the
Chris@223 284 // likelihood of arithmetic overflow
Chris@843 285 // cerr << "statvfs(" << path << ") says available: " << buf.f_bavail << ", block size: " << buf.f_bsize << endl;
Chris@223 286 uint64_t available = ((buf.f_bavail / 1024) * buf.f_bsize) / 1024;
Chris@223 287 if (available > INT_MAX) available = INT_MAX;
Chris@1038 288 return ssize_t(available);
Chris@223 289 } else {
Chris@223 290 perror("statvfs failed");
Chris@223 291 return -1;
Chris@223 292 }
Chris@223 293 #endif
Chris@223 294 }
Chris@303 295
Chris@835 296 #ifdef _WIN32
Chris@835 297 extern void SystemMemoryBarrier()
Chris@835 298 {
Chris@1218 299 #ifdef _MSC_VER
Chris@835 300 MemoryBarrier();
Chris@835 301 #else /* mingw */
Chris@835 302 LONG Barrier = 0;
Chris@835 303 __asm__ __volatile__("xchgl %%eax,%0 "
Chris@835 304 : "=r" (Barrier));
Chris@835 305 #endif
Chris@835 306 }
Chris@835 307 #else /* !_WIN32 */
Chris@1357 308 #if !defined(__APPLE__) && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0))
Chris@835 309 void
Chris@835 310 SystemMemoryBarrier()
Chris@835 311 {
Chris@835 312 pthread_mutex_t dummy = PTHREAD_MUTEX_INITIALIZER;
Chris@835 313 pthread_mutex_lock(&dummy);
Chris@835 314 pthread_mutex_unlock(&dummy);
Chris@835 315 }
Chris@835 316 #endif /* !defined(__APPLE__) etc */
Chris@835 317 #endif /* !_WIN32 */
Chris@835 318
Chris@835 319
Chris@1582 320 static char *startupLocale = nullptr;
Chris@303 321
Chris@303 322 void
Chris@303 323 StoreStartupLocale()
Chris@303 324 {
Chris@1582 325 char *loc = setlocale(LC_ALL, nullptr);
Chris@303 326 if (!loc) return;
Chris@303 327 if (startupLocale) free(startupLocale);
Chris@303 328 startupLocale = strdup(loc);
Chris@303 329 }
Chris@303 330
Chris@303 331 void
Chris@303 332 RestoreStartupLocale()
Chris@303 333 {
Chris@303 334 if (!startupLocale) {
Chris@303 335 setlocale(LC_ALL, "");
Chris@303 336 } else {
Chris@303 337 setlocale(LC_ALL, startupLocale);
Chris@303 338 }
Chris@303 339 }
Chris@223 340
Chris@1818 341 bool
Chris@1818 342 OSThemeIsDark()
Chris@1818 343 {
Chris@1818 344 SVCERR << "OSThemeIsDark() called" << endl;
Chris@1818 345 #ifdef _MSC_VER
Chris@1818 346 using namespace winrt::Windows::UI::ViewManagement;
Chris@1818 347 UISettings settings;
Chris@1818 348 auto background = settings.GetColorValue(UIColorType::Background);
Chris@1818 349 if (int(background.R) + int(background.G) + int(background.B) < 384) {
Chris@1818 350 return true;
Chris@1818 351 }
Chris@1818 352 #endif
Chris@1818 353 return false;
Chris@1818 354 }
Chris@1818 355
Chris@223 356 double mod(double x, double y) { return x - (y * floor(x / y)); }
Chris@223 357 float modf(float x, float y) { return x - (y * floorf(x / y)); }
Chris@223 358
Chris@223 359 double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; }
Chris@1039 360 float princargf(float a) { return float(princarg(a)); }
Chris@223 361
Chris@1475 362 bool
Chris@1475 363 getEnvUtf8(std::string variable, std::string &value)
Chris@1475 364 {
Chris@1475 365 value = "";
Chris@1475 366
Chris@1475 367 #ifdef _WIN32
Chris@1475 368 int wvarlen = MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 369 variable.c_str(), int(variable.length()),
Chris@1475 370 0, 0);
Chris@1475 371 if (wvarlen < 0) {
Chris@1475 372 SVCERR << "WARNING: Unable to convert environment variable name "
Chris@1475 373 << variable << " to wide characters" << endl;
Chris@1475 374 return false;
Chris@1475 375 }
Chris@1475 376
Chris@1475 377 wchar_t *wvarbuf = new wchar_t[wvarlen + 1];
Chris@1475 378 (void)MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 379 variable.c_str(), int(variable.length()),
Chris@1475 380 wvarbuf, wvarlen);
Chris@1475 381 wvarbuf[wvarlen] = L'\0';
Chris@1475 382
Chris@1475 383 wchar_t *wvalue = _wgetenv(wvarbuf);
Chris@1176 384
Chris@1475 385 delete[] wvarbuf;
Chris@1475 386
Chris@1475 387 if (!wvalue) {
Chris@1475 388 return false;
Chris@1475 389 }
Chris@1475 390
Chris@1480 391 int wvallen = int(wcslen(wvalue));
Chris@1475 392 int vallen = WideCharToMultiByte(CP_UTF8, 0,
Chris@1480 393 wvalue, wvallen,
Chris@1475 394 0, 0, 0, 0);
Chris@1475 395 if (vallen < 0) {
Chris@1475 396 SVCERR << "WARNING: Unable to convert environment value to UTF-8"
Chris@1475 397 << endl;
Chris@1475 398 return false;
Chris@1475 399 }
Chris@1475 400
Chris@1475 401 char *val = new char[vallen + 1];
Chris@1475 402 (void)WideCharToMultiByte(CP_UTF8, 0,
Chris@1480 403 wvalue, wvallen,
Chris@1475 404 val, vallen, 0, 0);
Chris@1475 405 val[vallen] = '\0';
Chris@1475 406
Chris@1475 407 value = val;
Chris@1475 408
Chris@1475 409 delete[] val;
Chris@1475 410 return true;
Chris@1475 411
Chris@1475 412 #else
Chris@1475 413
Chris@1475 414 char *val = getenv(variable.c_str());
Chris@1475 415 if (!val) {
Chris@1475 416 return false;
Chris@1475 417 }
Chris@1475 418
Chris@1475 419 value = val;
Chris@1475 420 return true;
Chris@1475 421
Chris@1475 422 #endif
Chris@1475 423 }
Chris@1475 424
Chris@1475 425 bool
Chris@1475 426 putEnvUtf8(std::string variable, std::string value)
Chris@1475 427 {
Chris@1477 428 #ifdef _WIN32
Chris@1475 429 std::string entry = variable + "=" + value;
Chris@1475 430
Chris@1475 431 int wentlen = MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 432 entry.c_str(), int(entry.length()),
Chris@1475 433 0, 0);
Chris@1475 434 if (wentlen < 0) {
Chris@1475 435 SVCERR << "WARNING: Unable to convert environment entry to "
Chris@1475 436 << "wide characters" << endl;
Chris@1475 437 return false;
Chris@1475 438 }
Chris@1475 439
Chris@1475 440 wchar_t *wentbuf = new wchar_t[wentlen + 1];
Chris@1475 441 (void)MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 442 entry.c_str(), int(entry.length()),
Chris@1475 443 wentbuf, wentlen);
Chris@1475 444 wentbuf[wentlen] = L'\0';
Chris@1475 445
Chris@1475 446 int rv = _wputenv(wentbuf);
Chris@1475 447
Chris@1475 448 delete[] wentbuf;
Chris@1475 449
Chris@1475 450 if (rv != 0) {
Chris@1475 451 SVCERR << "WARNING: Failed to set environment entry" << endl;
Chris@1475 452 return false;
Chris@1475 453 }
Chris@1475 454 return true;
Chris@1475 455
Chris@1475 456 #else
Chris@1475 457
Chris@1477 458 int rv = setenv(variable.c_str(), value.c_str(), 1);
Chris@1475 459 if (rv != 0) {
Chris@1475 460 SVCERR << "WARNING: Failed to set environment entry" << endl;
Chris@1475 461 return false;
Chris@1475 462 }
Chris@1475 463 return true;
Chris@1475 464
Chris@1475 465 #endif
Chris@1475 466 }
Chris@1475 467