LMMS
Loading...
Searching...
No Matches
juce_mac_ObjCHelpers.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23#include "juce_mac_CFHelpers.h"
24
25/* This file contains a few helper functions that are used internally but which
26 need to be kept away from the public headers because they use obj-C symbols.
27*/
28namespace juce
29{
30
31//==============================================================================
32inline Range<int> nsRangeToJuce (NSRange range)
33{
34 return { (int) range.location, (int) (range.location + range.length) };
35}
36
37inline NSRange juceRangeToNS (Range<int> range)
38{
39 return NSMakeRange ((NSUInteger) range.getStart(), (NSUInteger) range.getLength());
40}
41
42inline String nsStringToJuce (NSString* s)
43{
44 return CharPointer_UTF8 ([s UTF8String]);
45}
46
47inline NSString* juceStringToNS (const String& s)
48{
49 return [NSString stringWithUTF8String: s.toUTF8()];
50}
51
52inline NSString* nsStringLiteral (const char* const s) noexcept
53{
54 return [NSString stringWithUTF8String: s];
55}
56
57inline NSString* nsEmptyString() noexcept
58{
59 return [NSString string];
60}
61
62inline NSURL* createNSURLFromFile (const String& f)
63{
64 return [NSURL fileURLWithPath: juceStringToNS (f)];
65}
66
67inline NSURL* createNSURLFromFile (const File& f)
68{
69 return createNSURLFromFile (f.getFullPathName());
70}
71
72inline NSArray* createNSArrayFromStringArray (const StringArray& strings)
73{
74 auto array = [[NSMutableArray alloc] init];
75
76 for (auto string: strings)
77 [array addObject:juceStringToNS (string)];
78
79 return [array autorelease];
80}
81
82inline NSArray* varArrayToNSArray (const var& varToParse);
83
84inline NSDictionary* varObjectToNSDictionary (const var& varToParse)
85{
86 auto dictionary = [NSMutableDictionary dictionary];
87
88 if (varToParse.isObject())
89 {
90 auto* dynamicObject = varToParse.getDynamicObject();
91
92 auto& properties = dynamicObject->getProperties();
93
94 for (int i = 0; i < properties.size(); ++i)
95 {
96 auto* keyString = juceStringToNS (properties.getName (i).toString());
97
98 const var& valueVar = properties.getValueAt (i);
99
100 if (valueVar.isObject())
101 {
102 auto* valueDictionary = varObjectToNSDictionary (valueVar);
103
104 [dictionary setObject: valueDictionary forKey: keyString];
105 }
106 else if (valueVar.isArray())
107 {
108 auto* valueArray = varArrayToNSArray (valueVar);
109
110 [dictionary setObject: valueArray forKey: keyString];
111 }
112 else
113 {
114 auto* valueString = juceStringToNS (valueVar.toString());
115
116 [dictionary setObject: valueString forKey: keyString];
117 }
118 }
119 }
120
121 return dictionary;
122}
123
124inline NSArray* varArrayToNSArray (const var& varToParse)
125{
126 jassert (varToParse.isArray());
127
128 if (! varToParse.isArray())
129 return nil;
130
131 const auto* varArray = varToParse.getArray();
132
133 auto array = [NSMutableArray arrayWithCapacity: (NSUInteger) varArray->size()];
134
135 for (const auto& aVar : *varArray)
136 {
137 if (aVar.isObject())
138 {
139 auto* valueDictionary = varObjectToNSDictionary (aVar);
140
141 [array addObject: valueDictionary];
142 }
143 else if (aVar.isArray())
144 {
145 auto* valueArray = varArrayToNSArray (aVar);
146
147 [array addObject: valueArray];
148 }
149 else
150 {
151 auto* valueString = juceStringToNS (aVar.toString());
152
153 [array addObject: valueString];
154 }
155 }
156
157 return array;
158}
159
160var nsObjectToVar (NSObject* array);
161
162inline var nsDictionaryToVar (NSDictionary* dictionary)
163{
164 DynamicObject::Ptr dynamicObject (new DynamicObject());
165
166 for (NSString* key in dictionary)
167 dynamicObject->setProperty (nsStringToJuce (key), nsObjectToVar ([dictionary objectForKey: key]));
168
169 return var (dynamicObject.get());
170}
171
172inline var nsArrayToVar (NSArray* array)
173{
174 Array<var> resultArray;
175
176 for (id value in array)
177 resultArray.add (nsObjectToVar (value));
178
179 return var (resultArray);
180}
181
182inline var nsObjectToVar (NSObject* obj)
183{
184 if ([obj isKindOfClass: [NSString class]]) return nsStringToJuce ((NSString*) obj);
185 else if ([obj isKindOfClass: [NSNumber class]]) return nsStringToJuce ([(NSNumber*) obj stringValue]);
186 else if ([obj isKindOfClass: [NSDictionary class]]) return nsDictionaryToVar ((NSDictionary*) obj);
187 else if ([obj isKindOfClass: [NSArray class]]) return nsArrayToVar ((NSArray*) obj);
188 else
189 {
190 // Unsupported yet, add here!
192 }
193
194 return {};
195}
196
197#if JUCE_MAC
198template <typename RectangleType>
199NSRect makeNSRect (const RectangleType& r) noexcept
200{
201 return NSMakeRect (static_cast<CGFloat> (r.getX()),
202 static_cast<CGFloat> (r.getY()),
203 static_cast<CGFloat> (r.getWidth()),
204 static_cast<CGFloat> (r.getHeight()));
205}
206#endif
207
208#if JUCE_INTEL
209 template <typename T>
210 struct NeedsStret
211 {
212 #if JUCE_32BIT
213 static constexpr auto value = sizeof (T) > 8;
214 #else
215 static constexpr auto value = sizeof (T) > 16;
216 #endif
217 };
218
219 template <>
220 struct NeedsStret<void> { static constexpr auto value = false; };
221
222 template <typename T, bool b = NeedsStret<T>::value>
223 struct MetaSuperFn { static constexpr auto value = objc_msgSendSuper_stret; };
224
225 template <typename T>
226 struct MetaSuperFn<T, false> { static constexpr auto value = objc_msgSendSuper; };
227#else
228 template <typename>
229 struct MetaSuperFn { static constexpr auto value = objc_msgSendSuper; };
230#endif
231
232template <typename SuperType, typename ReturnType, typename... Params>
233inline ReturnType ObjCMsgSendSuper (id self, SEL sel, Params... params)
234{
235 using SuperFn = ReturnType (*) (struct objc_super*, SEL, Params...);
236 const auto fn = reinterpret_cast<SuperFn> (MetaSuperFn<ReturnType>::value);
237
238 objc_super s = { self, [SuperType class] };
239 return fn (&s, sel, params...);
240}
241
242//==============================================================================
244{
245 void operator() (NSObject* object) const noexcept
246 {
247 if (object != nullptr)
248 [object release];
249 }
250};
251
252template <typename NSType>
253using NSUniquePtr = std::unique_ptr<NSType, NSObjectDeleter>;
254
255/* This has very similar semantics to NSUniquePtr, with the main difference that it doesn't
256 automatically add a pointer to the managed type. This makes it possible to declare
257 scoped handles to id or block types.
258*/
259template <typename T>
261{
262public:
263 ObjCObjectHandle() = default;
264
265 // Note that this does *not* retain the argument.
266 explicit ObjCObjectHandle (T ptr) : item (ptr) {}
267
269
271 : item (other.item)
272 {
273 if (item != nullptr)
274 [item retain];
275 }
276
277 ObjCObjectHandle& operator= (const ObjCObjectHandle& other)
278 {
279 auto copy = other;
280 swap (copy);
281 return *this;
282 }
283
284 ObjCObjectHandle (ObjCObjectHandle&& other) noexcept { swap (other); }
285
286 ObjCObjectHandle& operator= (ObjCObjectHandle&& other) noexcept
287 {
288 reset();
289 swap (other);
290 return *this;
291 }
292
293 // Note that this does *not* retain the argument.
294 void reset (T ptr) { *this = ObjCObjectHandle { ptr }; }
295
296 T get() const { return item; }
297
298 void reset()
299 {
300 if (item != nullptr)
301 [item release];
302
303 item = {};
304 }
305
306 bool operator== (const ObjCObjectHandle& other) const { return item == other.item; }
307 bool operator!= (const ObjCObjectHandle& other) const { return ! (*this == other); }
308
309 bool operator== (std::nullptr_t) const { return item == nullptr; }
310 bool operator!= (std::nullptr_t) const { return ! (*this == nullptr); }
311
312private:
313 void swap (ObjCObjectHandle& other) noexcept { std::swap (other.item, item); }
314
315 T item{};
316};
317
318//==============================================================================
319namespace detail
320{
321 constexpr auto makeCompileTimeStr()
322 {
323 return std::array<char, 1> { { '\0' } };
324 }
325
326 template <typename A, size_t... As, typename B, size_t... Bs>
327 constexpr auto joinCompileTimeStrImpl (A&& a, std::index_sequence<As...>,
328 B&& b, std::index_sequence<Bs...>)
329 {
330 return std::array<char, sizeof... (As) + sizeof... (Bs) + 1> { { a[As]..., b[Bs]..., '\0' } };
331 }
332
333 template <size_t A, size_t B>
334 constexpr auto joinCompileTimeStr (const char (&a)[A], std::array<char, B> b)
335 {
336 return joinCompileTimeStrImpl (a, std::make_index_sequence<A - 1>(),
337 b, std::make_index_sequence<B - 1>());
338 }
339
340 template <size_t A, typename... Others>
341 constexpr auto makeCompileTimeStr (const char (&v)[A], Others&&... others)
342 {
343 return joinCompileTimeStr (v, makeCompileTimeStr (others...));
344 }
345} // namespace detail
346
347//==============================================================================
348template <typename Type>
349inline Type getIvar (id self, const char* name)
350{
351 void* v = nullptr;
352 object_getInstanceVariable (self, name, &v);
353 return static_cast<Type> (v);
354}
355
356template <typename SuperclassType>
358{
359 ObjCClass (const char* nameRoot)
360 : cls (objc_allocateClassPair ([SuperclassType class], getRandomisedName (nameRoot).toUTF8(), 0))
361 {
362 }
363
365 {
366 auto kvoSubclassName = String ("NSKVONotifying_") + class_getName (cls);
367
368 if (objc_getClass (kvoSubclassName.toUTF8()) == nullptr)
369 objc_disposeClassPair (cls);
370 }
371
373 {
374 objc_registerClassPair (cls);
375 }
376
377 SuperclassType* createInstance() const
378 {
379 return class_createInstance (cls, 0);
380 }
381
382 template <typename Type>
383 void addIvar (const char* name)
384 {
385 BOOL b = class_addIvar (cls, name, sizeof (Type), (uint8_t) rint (log2 (sizeof (Type))), @encode (Type));
386 jassert (b); ignoreUnused (b);
387 }
388
389 template <typename Result, typename... Args>
390 void addMethod (SEL selector, Result (*callbackFn) (id, SEL, Args...))
391 {
392 const auto s = detail::makeCompileTimeStr (@encode (Result), @encode (id), @encode (SEL), @encode (Args)...);
393 const auto b = class_addMethod (cls, selector, (IMP) callbackFn, s.data());
394 jassertquiet (b);
395 }
396
397 void addProtocol (Protocol* protocol)
398 {
399 BOOL b = class_addProtocol (cls, protocol);
400 jassert (b); ignoreUnused (b);
401 }
402
403 template <typename ReturnType, typename... Params>
404 static ReturnType sendSuperclassMessage (id self, SEL sel, Params... params)
405 {
406 return ObjCMsgSendSuper<SuperclassType, ReturnType, Params...> (self, sel, params...);
407 }
408
409 Class cls;
410
411private:
412 static String getRandomisedName (const char* root)
413 {
414 return root + String::toHexString (juce::Random::getSystemRandom().nextInt64());
415 }
416
418};
419
420//==============================================================================
421#ifndef DOXYGEN
422template <class JuceClass>
423struct ObjCLifetimeManagedClass : public ObjCClass<NSObject>
424{
426 : ObjCClass<NSObject> ("ObjCLifetimeManagedClass_")
427 {
428 addIvar<JuceClass*> ("cppObject");
429
430 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
433
434 addMethod (@selector (dealloc), dealloc);
435
437 }
438
439 static id initWithJuceObject (id _self, SEL, JuceClass* obj)
440 {
441 NSObject* self = sendSuperclassMessage<NSObject*> (_self, @selector (init));
442 object_setInstanceVariable (self, "cppObject", obj);
443
444 return self;
445 }
446
447 static void dealloc (id _self, SEL)
448 {
449 if (auto* obj = getIvar<JuceClass*> (_self, "cppObject"))
450 {
451 delete obj;
452 object_setInstanceVariable (_self, "cppObject", nullptr);
453 }
454
455 sendSuperclassMessage<void> (_self, @selector (dealloc));
456 }
457
459};
460
461template <typename Class>
463#endif
464
465// this will return an NSObject which takes ownership of the JUCE instance passed-in
466// This is useful to tie the life-time of a juce instance to the life-time of an NSObject
467template <typename Class>
468NSObject* createNSObjectFromJuceClass (Class* obj)
469{
470 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wobjc-method-access")
471 return [ObjCLifetimeManagedClass<Class>::objCLifetimeManagedClass.createInstance() initWithJuceObject:obj];
473}
474
475// Get the JUCE class instance that was tied to the life-time of an NSObject with the
476// function above
477template <typename Class>
478Class* getJuceClassFromNSObject (NSObject* obj)
479{
480 return obj != nullptr ? getIvar<Class*> (obj, "cppObject") : nullptr;
481}
482
483template <typename ReturnT, class Class, typename... Params>
484ReturnT (^CreateObjCBlock(Class* object, ReturnT (Class::*fn)(Params...))) (Params...)
485{
486 __block Class* _this = object;
487 __block ReturnT (Class::*_fn)(Params...) = fn;
488
489 return [[^ReturnT (Params... params) { return (_this->*_fn) (params...); } copy] autorelease];
490}
491
492template <typename BlockType>
494{
495public:
496 ObjCBlock() { block = nullptr; }
497 template <typename R, class C, typename... P>
498 ObjCBlock (C* _this, R (C::*fn)(P...)) : block (CreateObjCBlock (_this, fn)) {}
499 ObjCBlock (BlockType b) : block ([b copy]) {}
500 ObjCBlock& operator= (const BlockType& other) { if (block != nullptr) { [block release]; } block = [other copy]; return *this; }
501 bool operator== (const void* ptr) const { return ((const void*) block == ptr); }
502 bool operator!= (const void* ptr) const { return ((const void*) block != ptr); }
503 ~ObjCBlock() { if (block != nullptr) [block release]; }
504
505 operator BlockType() const { return block; }
506
507private:
508 BlockType block;
509};
510
511} // namespace juce
#define copy(x)
Definition ADnoteParameters.cpp:1011
#define noexcept
Definition DistrhoDefines.h:72
uint8_t a
Definition Spc_Cpu.h:141
static String toHexString(int number)
Definition String.cpp:1830
Definition juce_Array.h:56
void add(const ElementType &newElement)
Definition juce_Array.h:418
Definition juce_CharPointer_UTF8.h:35
Definition juce_DynamicObject.h:40
NamedValueSet & getProperties() noexcept
Definition juce_DynamicObject.h:99
ReferenceCountedObjectPtr< DynamicObject > Ptr
Definition juce_DynamicObject.h:47
virtual void setProperty(const Identifier &propertyName, const var &newValue)
Definition juce_DynamicObject.cpp:50
Definition juce_File.h:45
ObjCBlock(C *_this, R(C::*fn)(P...))
Definition juce_mac_ObjCHelpers.h:498
~ObjCBlock()
Definition juce_mac_ObjCHelpers.h:503
ObjCBlock()
Definition juce_mac_ObjCHelpers.h:496
ObjCBlock(BlockType b)
Definition juce_mac_ObjCHelpers.h:499
BlockType block
Definition juce_mac_ObjCHelpers.h:508
T get() const
Definition juce_mac_ObjCHelpers.h:296
ObjCObjectHandle(const ObjCObjectHandle &other)
Definition juce_mac_ObjCHelpers.h:270
T item
Definition juce_mac_ObjCHelpers.h:315
ObjCObjectHandle(ObjCObjectHandle &&other) noexcept
Definition juce_mac_ObjCHelpers.h:284
void swap(ObjCObjectHandle &other) noexcept
Definition juce_mac_ObjCHelpers.h:313
void reset(T ptr)
Definition juce_mac_ObjCHelpers.h:294
ObjCObjectHandle(T ptr)
Definition juce_mac_ObjCHelpers.h:266
~ObjCObjectHandle() noexcept
Definition juce_mac_ObjCHelpers.h:268
void reset()
Definition juce_mac_ObjCHelpers.h:298
Definition juce_Range.h:40
constexpr ValueType getStart() const noexcept
Definition juce_Range.h:80
constexpr ValueType getLength() const noexcept
Definition juce_Range.h:83
ReferencedType * get() const noexcept
Definition juce_ReferenceCountedObject.h:381
Definition juce_Result.h:57
Definition juce_StringArray.h:35
Definition juce_String.h:53
Definition juce_Variant.h:42
DynamicObject * getDynamicObject() const noexcept
Definition juce_Variant.cpp:575
Array< var > * getArray() const noexcept
Definition juce_Variant.cpp:573
bool isObject() const noexcept
Definition juce_Variant.cpp:560
String toString() const
Definition juce_Variant.cpp:570
bool isArray() const noexcept
Definition juce_Variant.cpp:561
unsigned v[N_MAX]
Definition inflate.c:1584
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
unsigned f
Definition inflate.c:1572
static PuglViewHint int value
Definition pugl.h:1708
static const char * name
Definition pugl.h:1582
void * object
Definition jmemsys.h:50
#define JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...)
Definition juce_CompilerWarnings.h:181
#define JUCE_END_IGNORE_WARNINGS_GCC_LIKE
Definition juce_CompilerWarnings.h:182
#define jassert(expression)
#define jassertquiet(expression)
#define JUCE_DECLARE_NON_COPYABLE(className)
#define jassertfalse
#define A(x)
Definition lice_arc.cpp:13
float in
Definition lilv_test.c:1460
unsigned char uint8_t
Definition mid.cpp:98
constexpr auto joinCompileTimeStr(const char(&a)[A], std::array< char, B > b)
Definition juce_mac_ObjCHelpers.h:334
constexpr auto joinCompileTimeStrImpl(A &&a, std::index_sequence< As... >, B &&b, std::index_sequence< Bs... >)
Definition juce_mac_ObjCHelpers.h:327
constexpr auto makeCompileTimeStr()
Definition juce_mac_ObjCHelpers.h:321
Definition carla_juce.cpp:31
NSRange juceRangeToNS(Range< int > range)
Definition juce_mac_ObjCHelpers.h:37
Class * getJuceClassFromNSObject(NSObject *obj)
Definition juce_mac_ObjCHelpers.h:478
NSString * nsStringLiteral(const char *const s) noexcept
Definition juce_mac_ObjCHelpers.h:52
NSObject * createNSObjectFromJuceClass(Class *obj)
Definition juce_mac_ObjCHelpers.h:468
NSURL * createNSURLFromFile(const String &f)
Definition juce_mac_ObjCHelpers.h:62
Range< int > nsRangeToJuce(NSRange range)
Definition juce_mac_ObjCHelpers.h:32
var nsArrayToVar(NSArray *array)
Definition juce_mac_ObjCHelpers.h:172
String nsStringToJuce(NSString *s)
Definition juce_mac_ObjCHelpers.h:42
NSString * nsEmptyString() noexcept
Definition juce_mac_ObjCHelpers.h:57
NSArray * varArrayToNSArray(const var &varToParse)
Definition juce_mac_ObjCHelpers.h:124
Type getIvar(id self, const char *name)
Definition juce_mac_ObjCHelpers.h:349
NSArray * createNSArrayFromStringArray(const StringArray &strings)
Definition juce_mac_ObjCHelpers.h:72
jack_client_t client jack_client_t client jack_client_t client jack_client_t JackInfoShutdownCallback void arg jack_client_t jack_port_t port void func jack_client_t const char const char unsigned long flags const jack_port_t port jack_client_t jack_port_id_t port_id const jack_port_t const char port_name const jack_port_t port void * ptr
Definition juce_linux_JackAudio.cpp:79
void ignoreUnused(Types &&...) noexcept
Definition juce_MathsFunctions.h:333
ReturnType ObjCMsgSendSuper(id self, SEL sel, Params... params)
Definition juce_mac_ObjCHelpers.h:233
std::unique_ptr< NSType, NSObjectDeleter > NSUniquePtr
Definition juce_mac_ObjCHelpers.h:253
ReturnT(^)(Params...) CreateObjCBlock(Class *object, ReturnT(Class::*fn)(Params...))
Definition juce_mac_ObjCHelpers.h:484
NSString * juceStringToNS(const String &s)
Definition juce_mac_ObjCHelpers.h:47
NSDictionary * varObjectToNSDictionary(const var &varToParse)
Definition juce_mac_ObjCHelpers.h:84
var nsObjectToVar(NSObject *array)
Definition juce_mac_ObjCHelpers.h:182
var nsDictionaryToVar(NSDictionary *dictionary)
Definition juce_mac_ObjCHelpers.h:162
#define false
Definition ordinals.h:83
#define P(protos)
Definition proto.h:37
Definition juce_mac_ObjCHelpers.h:229
static constexpr auto value
Definition juce_mac_ObjCHelpers.h:229
Definition juce_mac_ObjCHelpers.h:244
Definition juce_mac_ObjCHelpers.h:358
void addIvar(const char *name)
Definition juce_mac_ObjCHelpers.h:383
ObjCClass(const char *nameRoot)
Definition juce_mac_ObjCHelpers.h:359
~ObjCClass()
Definition juce_mac_ObjCHelpers.h:364
static String getRandomisedName(const char *root)
Definition juce_mac_ObjCHelpers.h:412
void addProtocol(Protocol *protocol)
Definition juce_mac_ObjCHelpers.h:397
void addMethod(SEL selector, Result(*callbackFn)(id, SEL, Args...))
Definition juce_mac_ObjCHelpers.h:390
SuperclassType * createInstance() const
Definition juce_mac_ObjCHelpers.h:377
static ReturnType sendSuperclassMessage(id self, SEL sel, Params... params)
Definition juce_mac_ObjCHelpers.h:404
Class cls
Definition juce_mac_ObjCHelpers.h:409
void registerClass()
Definition juce_mac_ObjCHelpers.h:372
Definition juce_mac_ObjCHelpers.h:424
ObjCLifetimeManagedClass()
Definition juce_mac_ObjCHelpers.h:425
static id initWithJuceObject(id _self, SEL, JuceClass *obj)
Definition juce_mac_ObjCHelpers.h:439
static void dealloc(id _self, SEL)
Definition juce_mac_ObjCHelpers.h:447
static ObjCLifetimeManagedClass objCLifetimeManagedClass
Definition juce_mac_ObjCHelpers.h:458
const char const char const char const char char * fn
Definition swell-functions.h:168
signed char BOOL
Definition swell-types.h:160
ZCONST char * key
Definition crypt.c:587
int r
Definition crypt.c:458
b
Definition crypt.c:628
ZCONST uch * init
Definition extract.c:2392
typedef int(UZ_EXP MsgFn)()
#define void
Definition unzip.h:396