diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoahelpers.h')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoahelpers.h | 153 |
1 files changed, 146 insertions, 7 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 0cf9cc0aff..84632c1487 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -55,11 +55,16 @@ #include <QtGui/qpalette.h> #include <QtGui/qscreen.h> +#include <objc/runtime.h> +#include <objc/message.h> + Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSView)); QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaWindow) +Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaDrawing) +Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaMouse) class QPixmap; class QString; @@ -82,13 +87,8 @@ QT_MANGLE_NAMESPACE(QNSView) *qnsview_cast(NSView *view); void qt_mac_transformProccessToForegroundApplication(); QString qt_mac_applicationName(); -int qt_mac_flipYCoordinate(int y); -qreal qt_mac_flipYCoordinate(qreal y); -QPointF qt_mac_flipPoint(const NSPoint &p); -NSPoint qt_mac_flipPoint(const QPoint &p); -NSPoint qt_mac_flipPoint(const QPointF &p); - -NSRect qt_mac_flipRect(const QRect &rect); +QPointF qt_mac_flip(const QPointF &pos, const QRectF &reference); +QRectF qt_mac_flip(const QRectF &rect, const QRectF &reference); Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); @@ -191,5 +191,144 @@ QT_END_NAMESPACE QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanelContentsWrapper); +// ------------------------------------------------------------------------- + +// QAppleRefCounted expects the retain function to return the object +io_object_t q_IOObjectRetain(io_object_t obj); +// QAppleRefCounted expects the release function to return void +void q_IOObjectRelease(io_object_t obj); + +template <typename T> +class QIOType : public QAppleRefCounted<T, io_object_t, q_IOObjectRetain, q_IOObjectRelease> +{ + using QAppleRefCounted<T, io_object_t, q_IOObjectRetain, q_IOObjectRelease>::QAppleRefCounted; +}; + +// ------------------------------------------------------------------------- + +// Depending on the ABI of the platform, we may need to use objc_msgSendSuper_stret: +// - http://www.sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html +// - https://lists.apple.com/archives/cocoa-dev/2008/Feb/msg02338.html +template <typename T> +struct objc_msgsend_requires_stret +{ static const bool value = +#if defined(Q_PROCESSOR_X86) + // Any return value larger than two registers on i386/x86_64 + sizeof(T) > sizeof(void*) * 2; +#elif defined(Q_PROCESSOR_ARM_32) + // Any return value larger than a single register on arm + sizeof(T) > sizeof(void*); +#elif defined(Q_PROCESSOR_ARM_64) + // Stret not used on arm64 + false; +#endif +}; + +template <> +struct objc_msgsend_requires_stret<void> +{ static const bool value = false; }; + +template <typename ReturnType, typename... Args> +ReturnType qt_msgSendSuper(id receiver, SEL selector, Args... args) +{ + static_assert(!objc_msgsend_requires_stret<ReturnType>::value, + "The given return type requires stret on this platform"); + + typedef ReturnType (*SuperFn)(objc_super *, SEL, Args...); + SuperFn superFn = reinterpret_cast<SuperFn>(objc_msgSendSuper); + objc_super sup = { receiver, [receiver superclass] }; + return superFn(&sup, selector, args...); +} + +template <typename ReturnType, typename... Args> +ReturnType qt_msgSendSuper_stret(id receiver, SEL selector, Args... args) +{ + static_assert(objc_msgsend_requires_stret<ReturnType>::value, + "The given return type does not use stret on this platform"); + + typedef void (*SuperStretFn)(ReturnType *, objc_super *, SEL, Args...); + SuperStretFn superStretFn = reinterpret_cast<SuperStretFn>(objc_msgSendSuper_stret); + + objc_super sup = { receiver, [receiver superclass] }; + ReturnType ret; + superStretFn(&ret, &sup, selector, args...); + return ret; +} + +template<typename... Args> +class QSendSuperHelper { +public: + QSendSuperHelper(id receiver, SEL sel, Args... args) + : m_receiver(receiver), m_selector(sel), m_args(std::make_tuple(args...)), m_sent(false) + { + } + + ~QSendSuperHelper() + { + if (!m_sent) + msgSendSuper<void>(m_args); + } + + template <typename ReturnType> + operator ReturnType() + { +#if defined(QT_DEBUG) + Method method = class_getInstanceMethod(object_getClass(m_receiver), m_selector); + char returnTypeEncoding[256]; + method_getReturnType(method, returnTypeEncoding, sizeof(returnTypeEncoding)); + NSUInteger alignedReturnTypeSize = 0; + NSGetSizeAndAlignment(returnTypeEncoding, nullptr, &alignedReturnTypeSize); + Q_ASSERT(alignedReturnTypeSize == sizeof(ReturnType)); +#endif + m_sent = true; + return msgSendSuper<ReturnType>(m_args); + } + +private: + template <std::size_t... Ts> + struct index {}; + + template <std::size_t N, std::size_t... Ts> + struct gen_seq : gen_seq<N - 1, N - 1, Ts...> {}; + + template <std::size_t... Ts> + struct gen_seq<0, Ts...> : index<Ts...> {}; + + template <typename ReturnType, bool V> + using if_requires_stret = typename std::enable_if<objc_msgsend_requires_stret<ReturnType>::value == V, ReturnType>::type; + + template <typename ReturnType, std::size_t... Is> + if_requires_stret<ReturnType, false> msgSendSuper(std::tuple<Args...>& args, index<Is...>) + { + return qt_msgSendSuper<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...); + } + + template <typename ReturnType, std::size_t... Is> + if_requires_stret<ReturnType, true> msgSendSuper(std::tuple<Args...>& args, index<Is...>) + { + return qt_msgSendSuper_stret<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...); + } + + template <typename ReturnType> + ReturnType msgSendSuper(std::tuple<Args...>& args) + { + return msgSendSuper<ReturnType>(args, gen_seq<sizeof...(Args)>{}); + } + + id m_receiver; + SEL m_selector; + std::tuple<Args...> m_args; + bool m_sent; +}; + +template<typename... Args> +QSendSuperHelper<Args...> qt_objcDynamicSuperHelper(id receiver, SEL selector, Args... args) +{ + return QSendSuperHelper<Args...>(receiver, selector, args...); +} + +// Same as calling super, but the super_class field resolved at runtime instead of compile time +#define qt_objcDynamicSuper(...) qt_objcDynamicSuperHelper(self, _cmd, ##__VA_ARGS__) + #endif //QCOCOAHELPERS_H |