diff options
Diffstat (limited to 'compat')
-rw-r--r-- | compat/CMakeLists.txt | 19 | ||||
-rw-r--r-- | compat/camera-names.cpp | 54 | ||||
-rw-r--r-- | compat/check-visible.cpp | 2 | ||||
-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/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/mutex.cpp | 30 | ||||
-rw-r--r-- | compat/mutex.hpp | 18 | ||||
-rw-r--r-- | compat/process-list.cpp | 195 | ||||
-rw-r--r-- | compat/process-list.hpp | 161 | ||||
-rw-r--r-- | compat/qt-dpi.hpp | 17 | ||||
-rw-r--r-- | compat/qt-signal.cpp | 12 | ||||
-rw-r--r-- | compat/qt-signal.hpp | 59 | ||||
-rw-r--r-- | compat/run-in-thread.hpp | 108 | ||||
-rw-r--r-- | compat/shm.cpp | 3 | ||||
-rw-r--r-- | compat/shm.h | 4 | ||||
-rw-r--r-- | compat/timer.cpp | 24 | ||||
-rw-r--r-- | compat/timer.hpp | 2 |
24 files changed, 593 insertions, 414 deletions
diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index fb498fb6..87b191cc 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) @@ -11,3 +7,18 @@ endif() if(WIN32) target_link_libraries(${self} strmiids) endif() + + +if(APPLE) + target_link_libraries(${self} proc) +elseif(LINUX) + otr_pkgconfig_(has-libproc2 ${self} libproc2) + if(has-libproc2) + target_compile_definitions(${self} PUBLIC -DOTR_HAS_LIBPROC2) + else() + otr_pkgconfig_(has-libprocps ${self} libprocps) + if(NOT has-libprocps) + message(FATAL_ERROR "install libproc2 or libprocps development files") + endif() + endif() +endif() diff --git a/compat/camera-names.cpp b/compat/camera-names.cpp index 5d190943..82776584 100644 --- a/compat/camera-names.cpp +++ b/compat/camera-names.cpp @@ -12,7 +12,8 @@ #endif #ifdef __APPLE__ -# include <QCameraInfo> +# include <QCameraDevice> +# include <QMediaDevices> #endif #ifdef __linux__ @@ -41,6 +42,36 @@ int camera_name_to_index(const QString &name) return -1; } +#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) +{ + // 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; @@ -67,26 +98,26 @@ std::vector<std::tuple<QString, int>> 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, ret.size() }); + 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 @@ -113,9 +144,8 @@ std::vector<std::tuple<QString, int>> get_camera_names() } #endif #ifdef __APPLE__ - QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); - for (const QCameraInfo &cameraInfo : cameras) - ret.push_back({ cameraInfo.description(), ret.size() }); + for (const QCameraDevice& camera_info : QMediaDevices::videoInputs()) + ret.push_back({ camera_info.description(), ret.size() }); #endif return ret; diff --git a/compat/check-visible.cpp b/compat/check-visible.cpp index 4da649c7..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; 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/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/mutex.cpp b/compat/mutex.cpp index 664677ea..71f42329 100644 --- a/compat/mutex.cpp +++ b/compat/mutex.cpp @@ -1,33 +1,31 @@ +#include "export.hpp" #include "mutex.hpp" #include <cstdlib> +#include <QMutex> +#include <QRecursiveMutex> -mutex& mutex::operator=(const mutex& rhs) +template<typename M> +mutex<M>& mutex<M>::operator=(const mutex& rhs) { - if (rhs->isRecursive() != inner.isRecursive()) - std::abort(); - return *this; } -mutex::mutex(const mutex& datum) : mutex{datum.inner.isRecursive() ? Recursive : NonRecursive} -{ -} +template<typename MutexType> MutexType* mutex<MutexType>::operator&() const { return &inner; } -mutex::mutex(RecursionMode m) : inner{m} -{ -} +template<typename M> mutex<M>::mutex(const mutex<M>& datum) {} +template<typename M> mutex<M>::mutex() = default; -QMutex* mutex::operator&() const noexcept +template<typename M> +mutex<M>::operator M*() const noexcept { return &inner; } -mutex::operator QMutex*() const noexcept +template<typename M> +M* mutex<M>::operator->() const noexcept { return &inner; } -QMutex* mutex::operator->() const noexcept -{ - return &inner; -} +template class OTR_COMPAT_EXPORT mutex<QMutex>; +template class OTR_COMPAT_EXPORT mutex<QRecursiveMutex>; diff --git a/compat/mutex.hpp b/compat/mutex.hpp index 54758a08..6ba4fa8c 100644 --- a/compat/mutex.hpp +++ b/compat/mutex.hpp @@ -1,24 +1,18 @@ #pragma once -#include <QMutex> - #include "export.hpp" +template<typename MutexType> class OTR_COMPAT_EXPORT mutex { - mutable QMutex inner; + mutable MutexType inner{}; public: - using RecursionMode = QMutex::RecursionMode; - static constexpr RecursionMode Recursive = RecursionMode::Recursive; - static constexpr RecursionMode NonRecursive = RecursionMode::NonRecursive; - mutex& operator=(const mutex& datum); + MutexType* operator&() const; mutex(const mutex& datum); - explicit mutex(RecursionMode m); - mutex() : mutex{NonRecursive} {} + explicit mutex(); - QMutex* operator&() const noexcept; - explicit operator QMutex*() const noexcept; - QMutex* operator->() const noexcept; + explicit operator MutexType*() const noexcept; + MutexType* operator->() const noexcept; }; diff --git a/compat/process-list.cpp b/compat/process-list.cpp new file mode 100644 index 00000000..34c83b06 --- /dev/null +++ b/compat/process-list.cpp @@ -0,0 +1,195 @@ +#include "process-list.hpp" + +#include <vector> +#include <QStringList> +#include <QDebug> + +#ifdef _WIN32 + +#include <windows.h> +#include <tlhelp32.h> + +QStringList get_all_executable_names() +{ + QStringList ret; + HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (h == INVALID_HANDLE_VALUE) + return ret; + + PROCESSENTRY32 e; + e.dwSize = sizeof(e); + + if (Process32First(h, &e) != TRUE) + { + CloseHandle(h); + return ret; + } + + do { + ret.append(QString{e.szExeFile}); + } while (Process32Next(h, &e) == TRUE); + + CloseHandle(h); + + return ret; +} + +#elif defined __APPLE__ + +#include <sys/sysctl.h> +#include <libproc.h> + +QStringList get_all_executable_names() +{ + QStringList ret; ret.reserve(512); + QList<int> vec; vec.reserve(512); + + while (true) + { + int numproc = proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0); + if (numproc == -1) + { + qDebug() << "proc_listpids numproc failed" << errno; + return ret; + } + vec.resize(numproc); + int cnt = proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(int) * numproc); + + if (cnt <= numproc) + { + std::vector<char> arglist; + int mib[2] { CTL_KERN, KERN_ARGMAX }; + size_t sz = sizeof(int); + int maxarg = 0; + if (sysctl(mib, 2, &maxarg, &sz, NULL, 0) == -1) + { + qDebug() << "sysctl KERN_ARGMAX" << errno; + return ret; + } + arglist.resize(maxarg); + for (int i = 0; i < numproc; i++) + { + size_t maxarg_ = (size_t)maxarg; + int mib[3] { CTL_KERN, KERN_PROCARGS2, vec[i] }; + if (sysctl(mib, 3, &arglist[0], &maxarg_, NULL, 0) == -1) + { + //qDebug() << "sysctl KERN_PROCARGS2" << vec[i] << errno; + continue; + } + QStringList cmdline; + for (unsigned j = sizeof(int) + strlen(&arglist[sizeof(int)]); j < maxarg_; j++) + { + QString arg(&arglist[j]); + if (arg.size() != 0) + { + cmdline << arg; + j += arg.size(); + } + } + if (cmdline.size() > 0) + { + int idx = cmdline[0].lastIndexOf('/'); + if (idx != -1) + { + QString tmp = cmdline[0].mid(idx+1); + if (cmdline.size() > 1 && (tmp == QStringLiteral("wine.bin") || tmp == QStringLiteral("wine"))) + { + idx = cmdline[1].lastIndexOf('/'); + if (idx == -1) + idx = cmdline[1].lastIndexOf('\\'); + if (idx != -1) + { + ret.append(cmdline[1].mid(idx+1)); + } + else + ret.append(cmdline[1]); + } + else + { + ret.append(tmp); + } + } + else + ret.append(cmdline[0]); + } + } + return ret; + } + } +} + +#elif defined __linux__ + +#include <cerrno> + +#ifdef OTR_HAS_LIBPROC2 +#include <libproc2/pids.h> +QStringList get_all_executable_names() +{ + QStringList ret; + 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(64); + + procps_pids_new(&info, items, 3); + + while ((stack = procps_pids_get(info, PIDS_FETCH_TASKS_ONLY))) + { + char **p_cmdline = PIDS_VAL(rel_cmdline, strv, stack, info); + + // 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> + +QStringList get_all_executable_names() +{ + QStringList ret; + proc_t** procs = readproctab(PROC_FILLCOM); + if (procs == nullptr) + { + qDebug() << "readproctab" << errno; + return ret; + } + for (int i = 0; procs[i]; i++) + { + // note, wine sets argv[0] so no parsing like in OSX case + auto proc = procs[i]; + if (proc->cmdline && proc->cmdline[0]) + { + QString tmp(proc->cmdline[0]); + const int idx = std::max(tmp.lastIndexOf('\\'), tmp.lastIndexOf('/')); + tmp = tmp.mid(idx == -1 ? 0 : idx+1); + ret.append(tmp); + } + freeproc(procs[i]); + } + free(procs); + return ret; +} +#endif + +#else +QStringList get_all_executable_names() { return {}; } + +#endif diff --git a/compat/process-list.hpp b/compat/process-list.hpp index 782dc0a4..323829bf 100644 --- a/compat/process-list.hpp +++ b/compat/process-list.hpp @@ -7,164 +7,7 @@ #pragma once -#include <QDebug> +#include "export.hpp" #include <QStringList> -#if defined _WIN32 - -#include <windows.h> -#include <tlhelp32.h> - -template<typename = void> -static QStringList get_all_executable_names() -{ - QStringList ret; - HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (h == INVALID_HANDLE_VALUE) - return ret; - - PROCESSENTRY32 e; - e.dwSize = sizeof(e); - - if (Process32First(h, &e) != TRUE) - { - CloseHandle(h); - return ret; - } - - do { - ret.append(e.szExeFile); - } while (Process32Next(h, &e) == TRUE); - - CloseHandle(h); - - return ret; -} -#elif defined __APPLE__ -#include <libproc.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/sysctl.h> -#include <cerrno> -#include <cstring> -#include <vector> - -template<typename = void> -static QStringList get_all_executable_names() -{ - QStringList ret; - std::vector<int> vec; - - while (true) - { - int numproc = proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0); - if (numproc == -1) - { - qDebug() << "proc_listpids numproc failed" << errno; - return ret; - } - vec.resize(numproc); - int cnt = proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(int) * numproc); - - if (cnt <= numproc) - { - std::vector<char> arglist; - int mib[2] { CTL_KERN, KERN_ARGMAX }; - size_t sz = sizeof(int); - int maxarg = 0; - if (sysctl(mib, 2, &maxarg, &sz, NULL, 0) == -1) - { - qDebug() << "sysctl KERN_ARGMAX" << errno; - return ret; - } - arglist.resize(maxarg); - for (int i = 0; i < numproc; i++) - { - size_t maxarg_ = (size_t)maxarg; - int mib[3] { CTL_KERN, KERN_PROCARGS2, vec[i] }; - if (sysctl(mib, 3, &arglist[0], &maxarg_, NULL, 0) == -1) - { - //qDebug() << "sysctl KERN_PROCARGS2" << vec[i] << errno; - continue; - } - QStringList cmdline; - for (unsigned j = sizeof(int) + strlen(&arglist[sizeof(int)]); j < maxarg_; j++) - { - QString arg(&arglist[j]); - if (arg.size() != 0) - { - cmdline << arg; - j += arg.size(); - } - } - if (cmdline.size() > 0) - { - int idx = cmdline[0].lastIndexOf('/'); - if (idx != -1) - { - QString tmp = cmdline[0].mid(idx+1); - if (cmdline.size() > 1 && (tmp == QStringLiteral("wine.bin") || tmp == QStringLiteral("wine"))) - { - idx = cmdline[1].lastIndexOf('/'); - if (idx == -1) - idx = cmdline[1].lastIndexOf('\\'); - if (idx != -1) - { - ret.append(cmdline[1].mid(idx+1)); - } - else - ret.append(cmdline[1]); - } - else - { - ret.append(tmp); - } - } - else - ret.append(cmdline[0]); - } - } - return ret; - } - } -} - -#elif defined __linux__ - -#include <proc/readproc.h> -#include <cerrno> - -template<typename = void> -QStringList get_all_executable_names() -{ - QStringList ret; - proc_t** procs = readproctab(PROC_FILLCOM); - if (procs == nullptr) - { - qDebug() << "readproctab" << errno; - return ret; - } - for (int i = 0; procs[i]; i++) - { - // note, wine sets argv[0] so no parsing like in OSX case - auto proc = procs[i]; - if (proc->cmdline && proc->cmdline[0]) - { - QString tmp(proc->cmdline[0]); - const int idx = std::max(tmp.lastIndexOf('\\'), tmp.lastIndexOf('/')); - tmp = tmp.mid(idx == -1 ? 0 : idx+1); - ret.append(tmp); - } - freeproc(procs[i]); - } - free(procs); - return ret; -} - -#else -template<typename = void> -static QStringList get_all_executable_names() -{ - return QStringList(); -} -#endif +OTR_COMPAT_EXPORT QStringList get_all_executable_names(); 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..92ab7e6f 100644 --- a/compat/qt-signal.hpp +++ b/compat/qt-signal.hpp @@ -4,27 +4,66 @@ #include "export.hpp" #include <QObject> +#include <QList> +#include <QPointF> +#include <QVariant> -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; } + +OTR_GENERATE_SIGNAL(int); +OTR_GENERATE_SIGNAL(double); +OTR_GENERATE_SIGNAL(float); +OTR_GENERATE_SIGNAL(bool); +OTR_GENERATE_SIGNAL(QString); +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.cpp b/compat/shm.cpp index f59469dc..341de40f 100644 --- a/compat/shm.cpp +++ b/compat/shm.cpp @@ -17,7 +17,7 @@ #ifdef QT_CORE_LIB # include <QDebug> -# define warn(str, ...) (qDebug() << "shm:" str ": " << __VA_ARGS__) +# define warn(str, ...) (qDebug() << "shm " str ": " << __VA_ARGS__) #else # define warn(str, ...) (void)0 #endif @@ -134,4 +134,3 @@ bool shm_wrapper::success() return mem != nullptr; #endif } - 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/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; }; |