diff options
Diffstat (limited to 'compat')
| -rw-r--r-- | compat/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | compat/camera-names.cpp | 78 | ||||
| -rw-r--r-- | compat/camera-names.hpp | 3 | ||||
| -rw-r--r-- | compat/check-visible.cpp | 11 | ||||
| -rw-r--r-- | compat/check-visible.hpp | 2 | ||||
| -rw-r--r-- | compat/correlation-calibrator.cpp | 3 | ||||
| -rw-r--r-- | compat/hamilton-tools.cpp | 109 | ||||
| -rw-r--r-- | compat/hamilton-tools.h | 76 | ||||
| -rw-r--r-- | compat/lang/de_DE.ts | 4 | ||||
| -rw-r--r-- | compat/lang/zh_CN.ts | 2 | ||||
| -rw-r--r-- | compat/linkage-macros.hpp | 20 | ||||
| -rw-r--r-- | compat/macros.h (renamed from compat/macros1.h) | 19 | ||||
| -rw-r--r-- | compat/macros.hpp | 25 | ||||
| -rw-r--r-- | compat/math.hpp | 59 | ||||
| -rw-r--r-- | compat/process-list.hpp | 60 | ||||
| -rw-r--r-- | compat/qhash.hpp | 26 | ||||
| -rw-r--r-- | compat/qt-dpi.hpp | 17 | ||||
| -rw-r--r-- | compat/qt-signal.cpp | 12 | ||||
| -rw-r--r-- | compat/qt-signal.hpp | 62 | ||||
| -rw-r--r-- | compat/run-in-thread.hpp | 108 | ||||
| -rw-r--r-- | compat/shm.h | 4 | ||||
| -rw-r--r-- | compat/thread-name.cpp | 14 | ||||
| -rw-r--r-- | compat/timer.cpp | 24 | ||||
| -rw-r--r-- | compat/timer.hpp | 2 |
24 files changed, 498 insertions, 246 deletions
diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index fb498fb6..dc81436d 100644 --- a/compat/CMakeLists.txt +++ b/compat/CMakeLists.txt @@ -1,7 +1,3 @@ -if(CMAKE_COMPILER_IS_GNUCXX) - add_compile_options(-fno-lto -fno-fast-math -fno-finite-math-only -O0) -endif() - otr_module(compat NO-COMPAT BIN) if(NOT WIN32 AND NOT APPLE) diff --git a/compat/camera-names.cpp b/compat/camera-names.cpp index 69926e5a..b9511037 100644 --- a/compat/camera-names.cpp +++ b/compat/camera-names.cpp @@ -7,11 +7,15 @@ # include <cwchar> # define NO_DSHOW_STRSAFE # include <dshow.h> -#elif defined(__unix) || defined(__linux) || defined(__APPLE__) +#elif defined(__unix) || defined(__linux__) || defined(__APPLE__) # include <unistd.h> #endif -#ifdef __linux +#ifdef __APPLE__ +# include <QCameraInfo> +#endif + +#ifdef __linux__ # include <fcntl.h> # include <sys/ioctl.h> # include <linux/videodev2.h> @@ -24,16 +28,52 @@ int camera_name_to_index(const QString &name) { auto list = get_camera_names(); - auto it = std::find(list.cbegin(), list.cend(), name); + auto it = std::find_if(list.cbegin(), list.cend(), [&name](const auto& tuple) { + const auto& [str, idx] = tuple; + return str == name; + }); if (it != list.cend()) - return std::distance(list.cbegin(), it); + { + const auto& [ str, idx ] = *it; + return idx; + } return -1; } -std::vector<QString> get_camera_names() +#ifdef _WIN32 +# include <QRegularExpression> + +static QString prop_to_qstring(IPropertyBag* pPropBag, const wchar_t* name) +{ + QString ret{}; + VARIANT var; + VariantInit(&var); + HRESULT hr = pPropBag->Read(name, &var, nullptr); + if (SUCCEEDED(hr)) + ret = QString{(const QChar*)var.bstrVal, int(std::wcslen(var.bstrVal))}; + VariantClear(&var); + return ret; +} + +static QString device_path_from_qstring(const QString& str) { - std::vector<QString> ret; + // language=RegExp prefix=R"/( suffix=)/" + static const QRegularExpression regexp{R"/(#vid_([0-9a-f]{4})&pid_([0-9a-f]{4})&mi_([0-9a-f]{2})#([^#]+))/", + QRegularExpression::CaseInsensitiveOption}; + auto match = regexp.match(str); + if (!match.hasMatch()) + return {}; + QString id = match.captured(4); + id.replace('&', '_'); + return id; +} + +#endif + +std::vector<std::tuple<QString, int>> get_camera_names() +{ + std::vector<std::tuple<QString, int>> ret; #ifdef _WIN32 // Create the System Device Enumerator. HRESULT hr; @@ -57,31 +97,31 @@ std::vector<QString> get_camera_names() { IPropertyBag *pPropBag; hr = pMoniker->BindToStorage(nullptr, nullptr, IID_IPropertyBag, (void **)&pPropBag); - if (SUCCEEDED(hr)) { + if (SUCCEEDED(hr)) { // To retrieve the filter's friendly name, do the following: - VARIANT var; - VariantInit(&var); - hr = pPropBag->Read(L"FriendlyName", &var, nullptr); if (SUCCEEDED(hr)) { - // Display the name in your UI somehow. - QString str((QChar*)var.bstrVal, int(std::wcslen(var.bstrVal))); - ret.push_back(str); + QString str = prop_to_qstring(pPropBag, L"FriendlyName"); + QString path = device_path_from_qstring(prop_to_qstring(pPropBag, L"DevicePath")); + if (!path.isNull()) + str += QStringLiteral(" [%1]").arg(path); + ret.push_back({ str, (int)ret.size() }); } - VariantClear(&var); pPropBag->Release(); } pMoniker->Release(); } pEnumCat->Release(); } +#if 0 else qDebug() << "failed CLSID_VideoInputDeviceCategory" << hr; +#endif pSysDevEnum->Release(); #endif -#ifdef __linux +#ifdef __linux__ for (int i = 0; i < 16; i++) { char buf[32]; snprintf(buf, sizeof(buf), "/dev/video%d", i); @@ -97,10 +137,16 @@ std::vector<QString> get_camera_names() close(fd); continue; } - ret.push_back(QString((const char*)video_cap.card)); + ret.push_back({ QString((const char*)video_cap.card), i}); close(fd); } } #endif +#ifdef __APPLE__ + QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); + for (const QCameraInfo &cameraInfo : cameras) + ret.push_back({ cameraInfo.description(), ret.size() }); +#endif + return ret; } diff --git a/compat/camera-names.hpp b/compat/camera-names.hpp index bda15e81..3585edfe 100644 --- a/compat/camera-names.hpp +++ b/compat/camera-names.hpp @@ -10,9 +10,10 @@ #include <vector> #include <QString> +# include <tuple> #include "export.hpp" -OTR_COMPAT_EXPORT std::vector<QString> get_camera_names(); +OTR_COMPAT_EXPORT std::vector<std::tuple<QString, int>> get_camera_names(); OTR_COMPAT_EXPORT int camera_name_to_index(const QString &name); diff --git a/compat/check-visible.cpp b/compat/check-visible.cpp index f786ca14..621d941a 100644 --- a/compat/check-visible.cpp +++ b/compat/check-visible.cpp @@ -10,7 +10,7 @@ static bool visible = true; #if defined _WIN32 #include "timer.hpp" -#include "macros.hpp" +#include "macros.h" static Timer timer; @@ -29,6 +29,15 @@ void set_is_visible(const QWidget& w, bool force) return; } + { + int ndisplays = GetSystemMetrics(SM_CMONITORS); + if (ndisplays > 1) + { + visible = true; + return; + } + } + HWND hwnd = (HWND)w.winId(); if (!force && timer.elapsed_ms() < (visible ? visible_timeout : invisible_timeout)) diff --git a/compat/check-visible.hpp b/compat/check-visible.hpp index e24260ab..6669b84d 100644 --- a/compat/check-visible.hpp +++ b/compat/check-visible.hpp @@ -1,7 +1,7 @@ #pragma once #include "export.hpp" -#include "macros1.h" +#include "macros.h" class QWidget; diff --git a/compat/correlation-calibrator.cpp b/compat/correlation-calibrator.cpp index 01f3b14f..07ef7d3d 100644 --- a/compat/correlation-calibrator.cpp +++ b/compat/correlation-calibrator.cpp @@ -2,6 +2,7 @@ #include "variance.hpp" #include "compat/math.hpp" #include "compat/meta.hpp" +#include "compat/macros.h" #include <cmath> #include <iterator> @@ -49,7 +50,7 @@ bool correlation_calibrator::check_buckets(const vec6& data) for (unsigned k = 0; k < 6; k++) { - const double val = clamp(data[k], min[k], max[k]); + const double val = std::clamp(data[k], min[k], max[k]); pos[k] = unsigned((val-min[k])/spacing[k]); if (pos[k] >= nbuckets[k]) diff --git a/compat/hamilton-tools.cpp b/compat/hamilton-tools.cpp new file mode 100644 index 00000000..eb0ef984 --- /dev/null +++ b/compat/hamilton-tools.cpp @@ -0,0 +1,109 @@ +#include "hamilton-tools.h" +#include <cmath> + +tQuat QuatFromAngleAxe(const double angle, const tVector& axe) +{ + double a = TO_RAD * 0.5 * angle; + double d = sin(a) / VectorLength(axe); + return ( tQuat ( + axe.v[0] * d, + axe.v[1] * d, + axe.v[2] * d, + cos(a) + ) + ); +} + +tQuat QuatMultiply(const tQuat& qL, const tQuat& qR) +{ + tQuat Q; + Q.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y; + Q.y = qL.w*qR.y + qL.y*qR.w + qL.z*qR.x - qL.x*qR.z; + Q.z = qL.w*qR.z + qL.z*qR.w + qL.x*qR.y - qL.y*qR.x; + Q.w = qL.w*qR.w - qL.x*qR.x - qL.y*qR.y - qL.z*qR.z; + return(Q); +} + +tQuat QuatFromYPR(const double YPR[]) +{ + tQuat Q, Qp, Qy; + Q = QuatFromAngleAxe( -YPR[2], {0, 0, 1} ); //Roll, Z axe + Qp = QuatFromAngleAxe( -YPR[1], {1, 0, 0} ); //Pitch, X axe + Qy = QuatFromAngleAxe( -YPR[0], {0, 1, 0} ); //Yaw, Y axe + + Q = QuatMultiply(Qp, Q); + return(QuatMultiply(Qy, Q)); +} + +void Normalize(tQuat& Q) +{ + double m = sqrt(Q.x*Q.x + Q.y*Q.y + Q.z*Q.z + Q.w*Q.w); + if (m > EPSILON) + { + m = 1 / m; + Q.x = Q.x * m; + Q.y = Q.y * m; + Q.z = Q.z * m; + Q.w = Q.w * m; + } + else Q = tQuat(0, 0, 0, 1); +} + +tQuat Slerp(const tQuat& S, const tQuat& D, const double alpha) +{ + // calc cosine of half angle + double cosin = S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w; + + // select nearest rotation direction + tQuat Q; + if (cosin < 0) + { + cosin = - cosin; + Q.x = - D.x; + Q.y = - D.y; + Q.z = - D.z; + Q.w = - D.w; + } + else Q = D; + + // calculate coefficients + double scale0, scale1; + if ((1.0 - cosin) > EPSILON) + { + double omega = acos(cosin); + double sinus = 1 / sin(omega); + scale0 = sin((1.0 - alpha) * omega) * sinus; + scale1 = sin(alpha * omega)* sinus; + } + else + { + scale0 = 1.0 - alpha; + scale1 = alpha; + } + + Q.x = scale0 * S.x + scale1 * Q.x; + Q.y = scale0 * S.y + scale1 * Q.y; + Q.z = scale0 * S.z + scale1 * Q.z; + Q.w = scale0 * S.w + scale1 * Q.w; + + Normalize(Q); + + return( Q ); +} + +void QuatToYPR(const tQuat& Q, double YPR[]) +{ + const double xx = Q.x * Q.x; + const double xy = Q.x * Q.y; + const double xz = Q.x * Q.z; + const double xw = Q.x * Q.w; + const double yy = Q.y * Q.y; + const double yz = Q.y * Q.z; + const double yw = Q.y * Q.w; + const double zz = Q.z * Q.z; + const double zw = Q.z * Q.w; + + YPR[0] = TO_DEG * ( -atan2( 2 * ( xz + yw ), 1 - 2 * ( xx + yy ) )); + YPR[1] = TO_DEG * ( asin ( 2 * ( yz - xw ) )); + YPR[2] = TO_DEG * ( -atan2( 2 * ( xy + zw ), 1 - 2 * ( xx + zz ) )); +} diff --git a/compat/hamilton-tools.h b/compat/hamilton-tools.h new file mode 100644 index 00000000..885e9f79 --- /dev/null +++ b/compat/hamilton-tools.h @@ -0,0 +1,76 @@ +#pragma once + +#include <algorithm> +#include "export.hpp" +#include "compat/math.hpp" + +constexpr double TO_RAD = (M_PI / 180); +constexpr double TO_DEG = (180 / M_PI); +constexpr double EPSILON = 1e-30; + +struct tVector +{ + double v[3]; + tVector(double X = 0, double Y = 0, double Z = 0) {v[0]=X; v[1]=Y; v[2]=Z;} + tVector(const double V[]) {v[0]=V[0]; v[1]=V[1]; v[2]=V[2];} + + void operator=(const tVector& other) + { + std::copy(other.v, other.v + 3, v); + } + inline const tVector operator+(const tVector& other) const + { + return tVector(v[0] + other.v[0], v[1] + other.v[1], v[2] + other.v[2]); + } + void operator+=(const tVector& other) + { + v[0] += other.v[0]; + v[1] += other.v[1]; + v[2] += other.v[2]; + } + const tVector operator-(const tVector& other) const + { + return tVector(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]); + } + void operator-=(const tVector& other) + { + v[0] -= other.v[0]; + v[1] -= other.v[1]; + v[2] -= other.v[2]; + } + const tVector operator*(double scalar) const + { + return tVector(v[0] * scalar, v[1] * scalar, v[2] * scalar); + } + void operator*=(double scalar) + { + v[0] *= scalar; + v[1] *= scalar; + v[2] *= scalar; + } + const tVector operator/(double scalar) const + { + return *this * (1.0 / scalar); + } + void operator/= (double scalar) + { + *this *= 1.0 / scalar; + } +}; + +struct tQuat +{ + double x, y, z, w; + tQuat(double X = 0, double Y = 0, double Z = 0, double W = 1) + {x = X; y = Y; z = Z; w = W;} +}; + +inline double VectorLength(const tVector& v) { return sqrt(v.v[0] * v.v[0] + v.v[1] * v.v[1] + v.v[2] * v.v[2]); } +inline double VectorDistance(const tVector& v1, const tVector& v2) { return VectorLength(v2 - v1); } +inline tVector Lerp(const tVector& s, const tVector& d, const double alpha) { return s + (d - s) * alpha; } +tQuat OTR_COMPAT_EXPORT QuatFromYPR(const double YPR[]); +tQuat OTR_COMPAT_EXPORT QuatMultiply(const tQuat& qL, const tQuat& qR); +inline tQuat QuatDivide(const tQuat& qL, const tQuat& qR) { return QuatMultiply(qL, tQuat(-qR.x, -qR.y, -qR.z, qR.w)); } +inline double AngleBetween(const tQuat& S, const tQuat& D) { return TO_DEG * 2 * acos(fabs(S.x * D.x + S.y * D.y + S.z * D.z + S.w * D.w)); } +tQuat OTR_COMPAT_EXPORT Slerp(const tQuat& S, const tQuat& D, const double alpha); +void OTR_COMPAT_EXPORT QuatToYPR(const tQuat& Q, double YPR[]); diff --git a/compat/lang/de_DE.ts b/compat/lang/de_DE.ts new file mode 100644 index 00000000..1552582e --- /dev/null +++ b/compat/lang/de_DE.ts @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="de_DE"> +</TS> diff --git a/compat/lang/zh_CN.ts b/compat/lang/zh_CN.ts index 6401616d..e5ca8aa9 100644 --- a/compat/lang/zh_CN.ts +++ b/compat/lang/zh_CN.ts @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> -<TS version="2.1"> +<TS version="2.1" language="zh_CN"> </TS> diff --git a/compat/linkage-macros.hpp b/compat/linkage-macros.hpp index 64c64bdb..f4d0104b 100644 --- a/compat/linkage-macros.hpp +++ b/compat/linkage-macros.hpp @@ -1,14 +1,16 @@ #pragma once -#if defined _MSC_VER -# define OTR_GENERIC_EXPORT __declspec(dllexport) -# define OTR_GENERIC_IMPORT __declspec(dllimport) -#elif defined _WIN32 && !defined __WINE__ -# define OTR_GENERIC_EXPORT __attribute__((dllexport, visibility ("default"))) -# define OTR_GENERIC_IMPORT __attribute__((dllimport)) -#else -# define OTR_GENERIC_EXPORT __attribute__((visibility ("default"))) -# define OTR_GENERIC_IMPORT +#ifndef OTR_GENERIC_EXPORT +# if defined _MSC_VER +# define OTR_GENERIC_EXPORT __declspec(dllexport) +# define OTR_GENERIC_IMPORT __declspec(dllimport) +# elif defined _WIN32 && !defined __WINE__ +# define OTR_GENERIC_EXPORT __attribute__((dllexport, visibility ("default"))) +# define OTR_GENERIC_IMPORT __attribute__((dllimport)) +# else +# define OTR_GENERIC_EXPORT __attribute__((visibility ("default"))) +# define OTR_GENERIC_IMPORT +# endif #endif #if defined __APPLE__ || defined __MINGW32__ diff --git a/compat/macros1.h b/compat/macros.h index 2ebfc4df..7de7fb86 100644 --- a/compat/macros1.h +++ b/compat/macros.h @@ -9,7 +9,7 @@ #if defined _MSC_VER # define force_inline __forceinline #else -# define force_inline __attribute__((always_inline)) +# define force_inline __attribute__((always_inline)) inline #endif #if !defined likely @@ -38,5 +38,20 @@ # define progn(...) ([&]() -> decltype(auto) { __VA_ARGS__ }()) # define eval_once2(expr, ctr) eval_once3(expr, ctr) # define eval_once3(expr, ctr) ([&] { [[maybe_unused]] static const char init_ ## ctr = ((void)(expr), 0); }()) -# define eval_once(expr) eval_once2(expr, __COUNTER__) +# ifdef QT_NO_DEBUG_OUTPUT +# define eval_once(expr) void() +# else +# define eval_once(expr) eval_once2(expr, __COUNTER__) +# endif + +#define OTR_DISABLE_MOVE_COPY(type) \ + type(const type&) = delete; \ + type(type&&) = delete; \ + type& operator=(const type&) = delete; \ + type& operator=(type&&) = delete +#endif + +#ifdef _MSC_VER +# define strncasecmp _strnicmp +# define strcasecmp _stricmp #endif diff --git a/compat/macros.hpp b/compat/macros.hpp deleted file mode 100644 index 497933cf..00000000 --- a/compat/macros.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "macros1.h" - -#include <utility> -#include <type_traits> - -// before C++20 -namespace cxx20_compat { - template<typename T> - struct remove_cvref { - using type = std::remove_cv_t<std::remove_reference_t<T>>; - }; -} // ns cxx20_compat - -template<typename t> -using remove_cvref_t = typename cxx20_compat::remove_cvref<t>::type; - -template<typename t> -using to_const_ref_t = std::add_lvalue_reference_t<std::add_const_t<remove_cvref_t<t>>>; - -template<typename t> -using cv_qualified = std::conditional_t<std::is_fundamental_v<remove_cvref_t<t>>, - remove_cvref_t<t>, - to_const_ref_t<t>>; diff --git a/compat/math.hpp b/compat/math.hpp index 34428cbd..c5981cc2 100644 --- a/compat/math.hpp +++ b/compat/math.hpp @@ -1,72 +1,15 @@ #pragma once -#include "macros.hpp" - #include <cmath> #include <type_traits> -namespace util_detail { - -template<typename n> -inline auto clamp_float(n val, n min_, n max_) -{ - return std::fmin(std::fmax(val, min_), max_); -} - -template<typename t> -struct clamp final -{ - static inline auto clamp_(t val, t min_, t max_) - { - if (unlikely(val > max_)) - return max_; - if (unlikely(val < min_)) - return min_; - return val; - } -}; - -template<> -struct clamp<float> -{ - static inline auto clamp_(float val, float min_, float max_) - { - return clamp_float(val, min_, max_); - } -}; - -template<> -struct clamp<double> -{ - static inline auto clamp_(double val, double min_, double max_) - { - return clamp_float(val, min_, max_); - } -}; - -} // ns util_detail - -template<typename t, typename u, typename v> -inline auto clamp(const t& val, const u& min, const v& max) -{ - using w = cv_qualified<decltype(val + min + max)>; - return util_detail::clamp<w>::clamp_(val, min, max); -} - template<typename t> -inline auto iround(t val) -> std::enable_if_t<std::is_floating_point_v<remove_cvref_t<t>>, int> +inline auto iround(t val) -> std::enable_if_t<std::is_floating_point_v<std::decay_t<t>>, int> { return (int)std::round(val); } -template<typename t> -inline auto uround(t val) -> std::enable_if_t<std::is_floating_point_v<remove_cvref_t<t>>, unsigned> -{ - return (unsigned)std::fmax(0, std::round(val)); -} - template <typename t> -force_inline constexpr int signum(const t& x) { return x < t{0} ? -1 : 1; diff --git a/compat/process-list.hpp b/compat/process-list.hpp index d1f9999f..39e12603 100644 --- a/compat/process-list.hpp +++ b/compat/process-list.hpp @@ -52,7 +52,7 @@ static QStringList get_all_executable_names() template<typename = void> static QStringList get_all_executable_names() { - QStringList ret; + QStringList ret; ret.reserve(2048); std::vector<int> vec; while (true) @@ -129,15 +129,68 @@ static QStringList get_all_executable_names() } } -#elif defined __linux +#elif defined __linux__ + +#include <cerrno> + +#ifdef OTR_HAS_LIBPROC2 +#include <libproc2/pids.h> +template<typename = void> +QStringList get_all_executable_names() +{ + QStringList ret; ret.reserve(2048); + enum pids_item items[] = { PIDS_ID_PID, PIDS_CMD, PIDS_CMDLINE_V }; + + enum rel_items { rel_pid, rel_cmd, rel_cmdline }; + struct pids_info *info = NULL; + struct pids_stack *stack; + QString tmp; tmp.reserve(255); + + procps_pids_new(&info, items, 3); + + // procps-ng version 4.0.5 removed an unused argument in PIDS_VAL() macro. + // cf. https://gitlab.com/procps-ng/procps/-/commit/967fdcfb06e20aad0f3 + + // Although the emitted machine code is identical, backward API + // compatibility was silently broken in the patch with no upgrade path + // (e.g. deprecating PIDS_VAL() while introducing PIDS_VAL2()). + + // Unfortunately, procps-ng doesn't include a #define for identifying its + // version. For these reasons the code below depends on undocumented ABI + // compatibility between procps-ng versions.. -sh 20241226 + +#define OPENTRACK_PIDS_VAL(i, type, stack) stack->head[i].result.type + + while ((stack = procps_pids_get(info, PIDS_FETCH_TASKS_ONLY))) + { + char **p_cmdline = OPENTRACK_PIDS_VAL(rel_cmdline, strv, stack); + + // note, wine sets argv[0] so no parsing like in OSX case + if (p_cmdline && p_cmdline[0] && p_cmdline[0][0] && + !(p_cmdline[0][0] == '-' && !p_cmdline[0][1])) + { + tmp = QString{p_cmdline[0]}; + const int idx = std::max(tmp.lastIndexOf('\\'), tmp.lastIndexOf('/')); + if (idx != -1) + tmp = tmp.mid(idx+1); + //qDebug() << "procps" << tmp; + ret.append(tmp); + } + } + //qDebug() << "-- procps end"; + + procps_pids_unref(&info); + return ret; +} +#else #include <proc/readproc.h> #include <cerrno> template<typename = void> QStringList get_all_executable_names() { - QStringList ret; + QStringList ret; ret.reserve(2048); proc_t** procs = readproctab(PROC_FILLCOM); if (procs == nullptr) { @@ -160,6 +213,7 @@ QStringList get_all_executable_names() free(procs); return ret; } +#endif #else template<typename = void> diff --git a/compat/qhash.hpp b/compat/qhash.hpp new file mode 100644 index 00000000..5286e97e --- /dev/null +++ b/compat/qhash.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include <functional> + +#include <QtGlobal> +#include <QString> +#include <QHashFunctions> + +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + +#include <cstdlib> + +namespace std { +template<> struct hash<QString> +{ + using argument_type = QString; + using result_type = std::size_t; + + std::size_t operator()(const QString& value) const noexcept + { + return (std::size_t) qHash(value); + } +}; +} + +#endif diff --git a/compat/qt-dpi.hpp b/compat/qt-dpi.hpp index 01659c8a..fc17a062 100644 --- a/compat/qt-dpi.hpp +++ b/compat/qt-dpi.hpp @@ -3,17 +3,22 @@ #include <algorithm> #include <QWidget> +static inline double screen_dpi(const QPaintDevice* widget) +{ + const auto& x = *widget; +#ifdef _WIN32 + return std::max(x.devicePixelRatioF(), 1.); +#else + return std::max(std::max(x.logicalDpiX()/(double)x.physicalDpiX(), x.devicePixelRatioF()), 1.); +#endif +} + template<typename self> struct screen_dpi_mixin { protected: double screen_dpi() const { - const auto& x = *static_cast<const self*>(this); -#ifdef _WIN32 - return std::max(x.devicePixelRatioF(), 1.); -#else - return std::max(std::max(x.logicalDpiX()/(double)x.physicalDpiX(), x.devicePixelRatioF()), 1.); -#endif + return ::screen_dpi(static_cast<const self*>(this)); } }; diff --git a/compat/qt-signal.cpp b/compat/qt-signal.cpp index 08aac663..8c23866b 100644 --- a/compat/qt-signal.cpp +++ b/compat/qt-signal.cpp @@ -1,13 +1,7 @@ +#define OTR_GENERATE_SIGNAL3(type) void sig_##type::operator()(const type& x) const { notify(x); } #include "qt-signal.hpp" +namespace _qt_sig_impl { -namespace qt_sig { +sig_void::sig_void(QObject* parent) : QObject(parent) {} -nullary::nullary(QObject* parent) : QObject(parent) {} -nullary::~nullary() = default; - -void nullary::operator()() const -{ - notify(); } - -} // ns qt_sig diff --git a/compat/qt-signal.hpp b/compat/qt-signal.hpp index 119e063c..f74de642 100644 --- a/compat/qt-signal.hpp +++ b/compat/qt-signal.hpp @@ -3,28 +3,70 @@ // this is to avoid dealing with QMetaObject for the time being -sh 20190203 #include "export.hpp" +namespace options { class slider_value; } #include <QObject> +#include <QList> -namespace qt_sig { +namespace _qt_sig_impl { -class OTR_COMPAT_EXPORT nullary : public QObject +template<typename t> struct sig; + +class OTR_COMPAT_EXPORT sig_void final : public QObject { Q_OBJECT public: template<typename t, typename F> - nullary(t* datum, F&& f, Qt::ConnectionType conntype = Qt::AutoConnection) : QObject(datum) + sig_void(t* datum, F&& f, Qt::ConnectionType conntype = Qt::AutoConnection) : QObject(datum) { - connect(this, &nullary::notify, datum, f, conntype); + connect(this, &sig_void::notify, datum, f, conntype); } - - nullary(QObject* parent = nullptr); - ~nullary() override; - - void operator()() const; + explicit sig_void(QObject* parent = nullptr); + void operator()() const { notify(); } signals: void notify() const; }; -} // ns qt_sig +template<> struct sig<void> { using t = sig_void; }; + +#ifndef OTR_GENERATE_SIGNAL3 +# define OTR_GENERATE_SIGNAL3(x) +#endif +#define OTR_GENERATE_SIGNAL2(type) \ + class OTR_COMPAT_EXPORT sig_##type final : public QObject \ + { \ + Q_OBJECT \ + public: \ + explicit sig_##type(QObject* parent = nullptr) : QObject(parent) {} \ + void operator()(const type& x) const; \ + Q_SIGNALS: \ + void notify(const type& x) const; \ + }; \ + OTR_GENERATE_SIGNAL3(type) + +# define OTR_GENERATE_SIGNAL(type) \ + OTR_GENERATE_SIGNAL2(type); \ + using qlist##type = QList<type>; \ + OTR_GENERATE_SIGNAL2(qlist##type); \ + template<> struct sig<type> { using t = sig_##type; }; \ + template<> struct sig<qlist##type> { using t = qlist##type; } + +using slider_value = options::slider_value; + +OTR_GENERATE_SIGNAL(int); +OTR_GENERATE_SIGNAL(double); +OTR_GENERATE_SIGNAL(float); +OTR_GENERATE_SIGNAL(bool); +OTR_GENERATE_SIGNAL(QString); +OTR_GENERATE_SIGNAL(slider_value); +OTR_GENERATE_SIGNAL(QPointF); +OTR_GENERATE_SIGNAL(QVariant); + +} // namespace _qt_sig_impl + +#undef OTR_GENERATE_SIGNAL2 +#undef OTR_GENERATE_SIGNAL + +template<typename t> using qt_signal = typename _qt_sig_impl::sig<t>::t; + diff --git a/compat/run-in-thread.hpp b/compat/run-in-thread.hpp index b8ffc179..c552c600 100644 --- a/compat/run-in-thread.hpp +++ b/compat/run-in-thread.hpp @@ -7,9 +7,6 @@ * copyright notice and this permission notice appear in all copies. */ -#include "macros.hpp" - -#include <cassert> #include <thread> #include <condition_variable> #include <utility> @@ -17,99 +14,56 @@ #include <QObject> #include <QThread> -namespace qt_impl_detail { - -template<typename t> -struct run_in_thread_traits +namespace impl_run_in_thread { +struct semaphore final { - using type = t; - using ret_type = t; - static inline void assign(t& lvalue, const t& rvalue) { lvalue = rvalue; } - static inline t pass(const t& val) { return val; } - template<typename F> static inline t call(F&& fun) { return std::move(fun()); } -}; + using lock_guard = std::unique_lock<std::mutex>; + std::mutex mtx; + std::condition_variable cvar; + bool flag = false; -template<typename u> -struct run_in_thread_traits<u&&> -{ - using t = typename std::remove_reference<u>::type; - using type = t; - using ret_type = u; - static inline void assign(t& lvalue, t&& rvalue) { lvalue = rvalue; } - static inline t&& pass(t&& val) { return val; } - template<typename F> static inline t&& call(F&& fun) { return std::move(fun()); } -}; + semaphore() = default; -template<> -struct run_in_thread_traits<void> -{ - using type = unsigned char; - using ret_type = void; - static inline void assign(unsigned char&, unsigned char&&) {} - static inline void pass(type&&) {} - template<typename F> static type call(F&& fun) { fun(); return type(0); } -}; + void wait() + { + lock_guard guard(mtx); + while (!flag) + cvar.wait(guard); + } + void notify() + { + lock_guard guard(mtx); + flag = true; + cvar.notify_one(); + } +}; } template<typename F> -auto never_inline -run_in_thread_sync(QObject* obj, F&& fun) - -> typename qt_impl_detail::run_in_thread_traits<decltype(fun())>::ret_type +void run_in_thread_sync(QObject* obj, F&& fun) { - using lock_guard = std::unique_lock<std::mutex>; + if (obj->thread() == QThread::currentThread()) + return (void)fun(); - using traits = qt_impl_detail::run_in_thread_traits<decltype(fun())>; - - typename traits::type ret; - - struct semaphore final - { - std::mutex mtx; - std::condition_variable cvar; - bool flag; - - semaphore() : flag(false) {} - - void wait() - { - lock_guard guard(mtx); - while (!flag) - cvar.wait(guard); - } - - void notify() - { - lock_guard guard(mtx); - flag = true; - cvar.notify_one(); - } - }; - - semaphore sem; + impl_run_in_thread::semaphore sem; { QObject src; - QObject::connect(&src, - &QObject::destroyed, - obj, - [&] { - traits::assign(ret, traits::call(fun)); - sem.notify(); - }, - Qt::AutoConnection); + QObject::connect(&src, &QObject::destroyed, + obj, [&] { fun(); sem.notify(); }, + Qt::QueuedConnection); } sem.wait(); - return traits::pass(std::move(ret)); } template<typename F> void run_in_thread_async(QObject* obj, F&& fun) { + if (obj->thread() == QThread::currentThread()) + return (void)fun(); + QObject src; - QThread* t = obj->thread(); - if (!t) abort(); - src.moveToThread(t); - QObject::connect(&src, &QObject::destroyed, obj, std::move(fun), Qt::AutoConnection); + QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun), Qt::QueuedConnection); } diff --git a/compat/shm.h b/compat/shm.h index d1363219..5036b335 100644 --- a/compat/shm.h +++ b/compat/shm.h @@ -20,7 +20,7 @@ #endif #include "export.hpp" -#include "macros1.h" +#include "macros.h" class OTR_COMPAT_EXPORT shm_wrapper final { @@ -39,4 +39,6 @@ public: bool unlock(); bool success(); inline void* ptr() { return mem; } + + OTR_DISABLE_MOVE_COPY(shm_wrapper); }; diff --git a/compat/thread-name.cpp b/compat/thread-name.cpp index 504c6f19..08a7d628 100644 --- a/compat/thread-name.cpp +++ b/compat/thread-name.cpp @@ -20,12 +20,9 @@ struct THREADNAME_INFO }; static inline -void set_curthread_name_old(const QString& name_) +void set_curthread_name_old_(const char* name) { - QByteArray str = name_.toLocal8Bit(); - const char* name = str.constData(); HANDLE curthread = GetCurrentThread(); - THREADNAME_INFO info; // NOLINT(cppcoreguidelines-pro-type-member-init) info.dwType = 0x1000; info.szName = name; @@ -41,6 +38,15 @@ void set_curthread_name_old(const QString& name_) { } } + +static inline +void set_curthread_name_old(const QString& name_) +{ + QByteArray str = name_.toLocal8Bit(); + const char* name = str.constData(); + + set_curthread_name_old_(name); +} #else static inline void set_curthread_name_old(const QString&) {} diff --git a/compat/timer.cpp b/compat/timer.cpp index f60e4f62..fdea185a 100644 --- a/compat/timer.cpp +++ b/compat/timer.cpp @@ -23,26 +23,24 @@ void Timer::start() gettime(&state); } -struct timespec Timer::gettime_() const +struct timespec Timer::get_delta() const { struct timespec ts; // NOLINT gettime(&ts); - unsigned long long a = ts.tv_sec, b = state.tv_sec; - int c = ts.tv_nsec, d = state.tv_nsec; - return { (time_t)(a - b), (long)(c - d) }; + return { ts.tv_sec - state.tv_sec, ts.tv_nsec - state.tv_nsec }; } // milliseconds double Timer::elapsed_ms() const { - struct timespec delta = gettime_(); + struct timespec delta = get_delta(); return delta.tv_sec * 1000 + delta.tv_nsec * 1e-6; } double Timer::elapsed_seconds() const { - struct timespec delta = gettime_(); + struct timespec delta = get_delta(); return delta.tv_sec + delta.tv_nsec * 1e-9; } @@ -63,20 +61,14 @@ static auto otr_get_clock_frequency() void Timer::gettime(timespec* state) { - static const unsigned long long freq = otr_get_clock_frequency(); + static const auto freq = otr_get_clock_frequency(); LARGE_INTEGER d; BOOL ret = QueryPerformanceCounter(&d); assert(ret && "QueryPerformanceCounter failed"); - constexpr int usec = 1000000; - unsigned long long tm = d.QuadPart; - tm *= usec; - tm /= freq; - tm %= usec; - tm *= 1000; - - state->tv_sec = (time_t)((unsigned long long)d.QuadPart/freq); - state->tv_nsec = (long)tm; + constexpr int nsec = 1'000'000 * 1000; + state->tv_sec = (time_t)(d.QuadPart/freq); + state->tv_nsec = (decltype(state->tv_nsec))(d.QuadPart % freq * nsec / freq); } #elif defined __MACH__ diff --git a/compat/timer.hpp b/compat/timer.hpp index f7791a1a..47072226 100644 --- a/compat/timer.hpp +++ b/compat/timer.hpp @@ -23,6 +23,6 @@ struct OTR_COMPAT_EXPORT Timer final private: struct timespec state {}; static void gettime(struct timespec* state); - struct timespec gettime_() const; + struct timespec get_delta() const; using ns = time_units::ns; }; |
