summaryrefslogtreecommitdiffhomepage
path: root/compat
diff options
context:
space:
mode:
Diffstat (limited to 'compat')
-rw-r--r--compat/CMakeLists.txt4
-rw-r--r--compat/camera-names.cpp78
-rw-r--r--compat/camera-names.hpp3
-rw-r--r--compat/check-visible.cpp11
-rw-r--r--compat/check-visible.hpp2
-rw-r--r--compat/correlation-calibrator.cpp3
-rw-r--r--compat/hamilton-tools.cpp109
-rw-r--r--compat/hamilton-tools.h76
-rw-r--r--compat/lang/de_DE.ts4
-rw-r--r--compat/lang/zh_CN.ts2
-rw-r--r--compat/linkage-macros.hpp20
-rw-r--r--compat/macros.h (renamed from compat/macros1.h)19
-rw-r--r--compat/macros.hpp25
-rw-r--r--compat/math.hpp59
-rw-r--r--compat/process-list.hpp60
-rw-r--r--compat/qhash.hpp26
-rw-r--r--compat/qt-dpi.hpp17
-rw-r--r--compat/qt-signal.cpp12
-rw-r--r--compat/qt-signal.hpp62
-rw-r--r--compat/run-in-thread.hpp108
-rw-r--r--compat/shm.h4
-rw-r--r--compat/thread-name.cpp14
-rw-r--r--compat/timer.cpp24
-rw-r--r--compat/timer.hpp2
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;
};