1 /**
2 Dynamic bindings to the Foundation framework.
3 
4 Copyright: Guillaume Piolat 2016.
5 License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6 */
7 module derelict.cocoa.foundation;
8 
9 import std.string;
10 import std.utf;
11 
12 import dplug.core.nogc;
13 
14 import derelict.cocoa.runtime;
15 
16 
17 // NSZone
18 
19 extern (C) nothrow @nogc
20 {
21     alias void* function(NSUInteger bytes) pfNSAllocateMemoryPages;
22     alias void function (void* ptr, NSUInteger bytes) pfNSDeallocateMemoryPages;
23     alias void function(id format, ...) pfNSLog;
24 }
25 
26 __gshared
27 {
28     pfNSDeallocateMemoryPages NSDeallocateMemoryPages;
29     pfNSAllocateMemoryPages NSAllocateMemoryPages;
30     pfNSLog NSLog;
31 }
32 
33 __gshared
34 {
35     //NSString NSDefaultRunLoopMode;
36     NSString NSRunLoopCommonModes;
37 }
38 
39 alias NSTimeInterval = double;
40 
41 
42 // Mixin'd by all Cocoa objects
43 mixin template NSObjectTemplate(T, string className)
44 {
45 nothrow @nogc:
46 
47     // create from an id
48     this (id id_)
49     {
50         this._id = id_;
51     }
52 
53     /// Allocates, but do not init
54     static T alloc()
55     {
56         alias fun_t = extern(C) id function (id obj, SEL sel) nothrow @nogc;
57         return T( (cast(fun_t)objc_msgSend)(getClassID(), sel!"alloc") );
58     }
59 
60     static Class getClass()
61     {
62         return cast(Class)( lazyClass!className() );
63     }
64 
65     static id getClassID()
66     {
67         return lazyClass!className();
68     }
69 }
70 
71 struct NSObject
72 {
73 nothrow @nogc:
74 
75     // The only field available in all NSObject hierarchy
76     // That makes all these destructs idempotent with an id,
77     // and the size of a pointer.
78     id _id = null;
79 
80     // Subtype id
81     bool opCast()
82     {
83         return _id != null;
84     }
85 
86     mixin NSObjectTemplate!(NSObject, "NSObject");
87 
88     ~this()
89     {
90     }
91 
92     NSObject init_()
93     {
94         alias fun_t = extern(C) id function (id, const(SEL)) nothrow @nogc;
95         id result = (cast(fun_t)objc_msgSend)(_id, sel!"init");
96         return NSObject(result);
97     }
98 
99     void retain()
100     {
101         alias fun_t = extern(C) void function (id, const(SEL)) nothrow @nogc;
102         (cast(fun_t)objc_msgSend)(_id, sel!"retain");
103     }
104 
105     void release()
106     {
107         alias fun_t = extern(C) void function (id, const(SEL)) nothrow @nogc;
108         (cast(fun_t)objc_msgSend)(_id, sel!"release");
109     }
110 }
111 
112 struct NSData
113 {
114 nothrow @nogc:
115 
116     NSObject parent;
117     alias parent this;
118 
119     mixin NSObjectTemplate!(NSData, "NSData");
120 
121     static NSData data()
122     {
123         alias fun_t = extern(C) id function (id obj, const(SEL) sel) nothrow @nogc;
124         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"data");
125         return NSData(result);
126     }
127 
128     static NSData dataWithBytesNoCopy(void* bytes, NSUInteger length, bool freeWhenDone)
129     {
130         alias fun_t = extern(C) id function(id, const(SEL), void*, NSUInteger, BOOL) nothrow @nogc;
131         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"dataWithBytesNoCopy:length:freeWhenDone:",
132             bytes, length, freeWhenDone ? YES : NO);
133         return NSData(result);
134     }
135 }
136 
137 struct NSString
138 {
139 nothrow @nogc:
140 
141     NSObject parent;
142     alias parent this;
143 
144     mixin NSObjectTemplate!(NSString, "NSString");
145 
146     static NSString stringWith (wstring str) nothrow @nogc
147     {
148         alias fun_t = extern(C) id function(id, SEL, const(wchar)*, NSUInteger) nothrow @nogc;
149         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"stringWithCharacters:length:",
150                                  CString16(str).storage, cast(NSUInteger)(str.length));
151         return NSString(result);
152     }
153 
154     size_t length ()
155     {
156         alias fun_t = extern(C) NSUInteger function(id, SEL) nothrow @nogc;
157         return cast(size_t)( (cast(fun_t)objc_msgSend)(_id, sel!"length") );
158     }
159 
160     char* UTF8String ()
161     {
162         alias fun_t = extern(C) char* function(id, SEL) nothrow @nogc;
163         return (cast(fun_t)objc_msgSend)(_id, sel!"UTF8String");
164     }
165 
166     void getCharacters (wchar* buffer, NSRange range)
167     {
168         alias fun_t = extern(C) void function(id, SEL, wchar*, NSRange) nothrow @nogc;
169         (cast(fun_t)objc_msgSend)(_id, sel!"getCharacters:range:", buffer, range);
170     }
171 
172     NSString stringWithCharacters (wchar* chars, size_t length)
173     {
174         alias fun_t = extern(C) id function(id, SEL, wchar*, NSUInteger) nothrow @nogc;
175         id result = (cast(fun_t)objc_msgSend)(_id, sel!"stringWithCharacters:length:", chars, cast(NSUInteger)length);
176         return NSString(result);
177     }
178 
179     NSRange rangeOfString (NSString aString)
180     {
181         alias fun_t = extern(C) NSRange function(id, SEL, id) nothrow @nogc;
182         return (cast(fun_t)objc_msgSend)(_id, sel!"rangeOfString", aString._id);
183     }
184 
185     NSString stringByAppendingString (NSString aString)
186     {
187         alias fun_t = extern(C) id function(id, SEL, id) nothrow @nogc;
188         id result = (cast(fun_t)objc_msgSend)(_id, sel!"stringByAppendingString:", aString._id);
189         return NSString(result);
190     }
191 
192     /// Returns: The character at a given UTF-16 code unit index.
193     wchar characterAtIndex(int index)
194     {
195         alias fun_t = extern(C) wchar function(id, SEL, NSUInteger) nothrow @nogc;
196         return (cast(fun_t)objc_msgSend)(_id, sel!"characterAtIndex:", cast(NSUInteger)index);
197     }
198 }
199 
200 struct NSURL
201 {
202 nothrow @nogc:
203     NSObject parent;
204     alias parent this;
205 
206     mixin NSObjectTemplate!(NSURL, "NSURL");
207 
208     static NSURL URLWithString(NSString str)
209     {
210         alias fun_t = extern(C) id function(id, SEL, id) nothrow @nogc;
211         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"URLWithString:", str._id);
212         return NSURL(result);
213     }
214 
215 }
216 
217 struct NSEnumerator
218 {
219 nothrow @nogc:
220     NSObject parent;
221     alias parent this;
222 
223     mixin NSObjectTemplate!(NSEnumerator, "NSEnumerator");
224 
225     id nextObject ()
226     {
227         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
228         return (cast(fun_t)objc_msgSend)(_id, sel!"nextObject");
229     }
230 }
231 
232 struct NSArray
233 {
234 nothrow @nogc:
235 
236     NSObject parent;
237     alias parent this;
238 
239     mixin NSObjectTemplate!(NSArray, "NSArray");
240 
241     NSEnumerator objectEnumerator ()
242     {
243         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
244         id result = (cast(fun_t)objc_msgSend)(_id, sel!"objectEnumerator");
245         return NSEnumerator(result);
246     }
247 }
248 
249 
250 struct NSProcessInfo
251 {
252 nothrow @nogc:
253 
254     NSObject parent;
255     alias parent this;
256 
257     mixin NSObjectTemplate!(NSProcessInfo, "NSProcessInfo");
258 
259     static NSProcessInfo processInfo ()
260     {
261         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
262         id result = (cast(fun_t)objc_msgSend)(lazyClass!"NSProcessInfo", sel!"processInfo");
263         return NSProcessInfo(result);
264     }
265 
266     NSString processName ()
267     {
268         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
269         id result = (cast(fun_t)objc_msgSend)(_id, sel!"processName");
270         return NSString(result);
271     }
272 }
273 
274 struct NSNotification
275 {
276 nothrow @nogc:
277     NSObject parent;
278     alias parent this;
279 
280     mixin NSObjectTemplate!(NSNotification, "NSNotification");
281 }
282 
283 struct NSDictionary
284 {
285 nothrow @nogc:
286     NSObject parent;
287     alias parent this;
288 
289     mixin NSObjectTemplate!(NSDictionary, "NSDictionary");
290 
291     static NSDictionary dictionaryWithObjectsAndKeys(Args...)(id firstObject, Args args)
292     {
293         alias fun_t = extern(C) id function(id, SEL, id, ...) nothrow @nogc;
294         auto result = (cast(fun_t) objc_msgSend)(getClassID(), sel!"dictionaryWithObjectsAndKeys:", firstObject, args);
295 
296         return NSDictionary(result);
297     }
298 
299     id objectForKey(id key)
300     {
301         alias fun_t = extern(C) id function(id, SEL, id) nothrow @nogc;
302         id result = (cast(fun_t)objc_msgSend)(_id, sel!"objectForKey:", key);
303         return result;
304     }
305 }
306 
307 struct NSAutoreleasePool
308 {
309 nothrow @nogc:
310     NSObject parent;
311     alias parent this;
312 
313     mixin NSObjectTemplate!(NSAutoreleasePool, "NSAutoreleasePool");
314 }
315 
316 enum : int
317 {
318     NSFileErrorMaximum = 1023,
319     NSFileErrorMinimum = 0,
320     NSFileLockingError = 255,
321     NSFileNoSuchFileError = 4,
322     NSFileReadCorruptFileError = 259,
323     NSFileReadInapplicableStringEncodingError = 261,
324     NSFileReadInvalidFileNameError = 258,
325     NSFileReadNoPermissionError = 257,
326     NSFileReadNoSuchFileError = 260,
327     NSFileReadUnknownError = 256,
328     NSFileReadUnsupportedSchemeError = 262,
329     NSFileWriteInapplicableStringEncodingError = 517,
330     NSFileWriteInvalidFileNameError = 514,
331     NSFileWriteNoPermissionError = 513,
332     NSFileWriteOutOfSpaceError = 640,
333     NSFileWriteUnknownError = 512,
334     NSFileWriteUnsupportedSchemeError = 518,
335     NSFormattingError = 2048,
336     NSFormattingErrorMaximum = 2559,
337     NSFormattingErrorMinimum = 2048,
338     NSKeyValueValidationError = 1024,
339     NSUserCancelledError = 3072,
340     NSValidationErrorMaximum = 2047,
341     NSValidationErrorMinimum = 1024,
342 
343     NSExecutableArchitectureMismatchError = 3585,
344     NSExecutableErrorMaximum = 3839,
345     NSExecutableErrorMinimum = 3584,
346     NSExecutableLinkError = 3588,
347     NSExecutableLoadError = 3587,
348     NSExecutableNotLoadableError = 3584,
349     NSExecutableRuntimeMismatchError = 3586,
350     NSFileReadTooLargeError = 263,
351     NSFileReadUnknownStringEncodingError = 264,
352 
353     GSFoundationPlaceHolderError = 9999
354 }
355 
356 struct NSError
357 {
358 nothrow @nogc:
359     NSObject parent;
360     alias parent this;
361 
362     mixin NSObjectTemplate!(NSError, "NSError");
363 
364     NSString localizedDescription()
365     {
366         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
367         id res = (cast(fun_t)objc_msgSend)(_id, sel!"localizedDescription");
368         return NSString(res);
369     }
370 }
371 
372 struct NSBundle
373 {
374 nothrow @nogc:
375     NSObject parent;
376     alias parent this;
377 
378     mixin NSObjectTemplate!(NSBundle, "NSBundle");
379 
380     void initWithPath(NSString path)
381     {
382         alias fun_t = extern(C) void function(id, SEL, id) nothrow @nogc;
383         (cast(fun_t)objc_msgSend)(_id, sel!"initWithPath:", path._id);
384     }
385 
386     bool load()
387     {
388         alias fun_t = extern(C) BOOL function(id, SEL) nothrow @nogc;
389         return (cast(fun_t)objc_msgSend)(_id, sel!"load") != NO;
390     }
391 
392     bool unload()
393     {
394         alias fun_t = extern(C) BOOL function(id, SEL) nothrow @nogc;
395         return (cast(fun_t)objc_msgSend)(_id, sel!"unload") != NO;
396     }
397 
398     bool loadAndReturnError(NSError error)
399     {
400         alias fun_t = extern(C) BOOL function(id, SEL, id) nothrow @nogc;
401         return (cast(fun_t)objc_msgSend)(_id, sel!"loadAndReturnError:", error._id) != NO;
402     }
403 }
404 
405 struct NSTimer
406 {
407 nothrow @nogc:
408     NSObject parent;
409     alias parent this;
410 
411     mixin NSObjectTemplate!(NSTimer, "NSTimer");
412 
413     static NSTimer timerWithTimeInterval(double seconds, NSObject target, SEL selector, void* userInfo, bool repeats)
414     {
415         alias fun_t = extern(C) id function(id, SEL, double, id, SEL, id, BOOL) nothrow @nogc;
416         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"timerWithTimeInterval:target:selector:userInfo:repeats:",
417                     seconds, target._id, selector, cast(id)userInfo, repeats ? YES : NO);
418         return NSTimer(result);
419     }
420 
421     void invalidate()
422     {
423         alias fun_t = extern(C) void function(id, SEL) nothrow @nogc;
424         (cast(fun_t)objc_msgSend)(_id, sel!"invalidate");
425     }
426 }
427 
428 struct NSRunLoop
429 {
430 nothrow @nogc:
431     NSObject parent;
432     alias parent this;
433 
434     mixin NSObjectTemplate!(NSRunLoop, "NSRunLoop");
435 
436     static NSRunLoop currentRunLoop()
437     {
438         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
439         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"currentRunLoop");
440         return NSRunLoop(result);
441     }
442 
443     static NSRunLoop mainRunLoop()
444     {
445         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
446         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"mainRunLoop");
447         return NSRunLoop(result);
448     }
449 
450     void runUntilDate(NSDate limitDate)
451     {
452         alias fun_t = extern(C) void function(id, SEL, id) nothrow @nogc;
453         (cast(fun_t)objc_msgSend)(_id, sel!"runUntilDate:", limitDate._id);
454     }
455 
456     void addTimer(NSTimer aTimer, NSString forMode)
457     {
458         alias fun_t = extern(C) void function(id, SEL, id, id) nothrow @nogc;
459         (cast(fun_t)objc_msgSend)(_id, sel!"addTimer:forMode:", aTimer._id, forMode._id);
460     }
461 }
462 
463 struct NSDate
464 {
465 nothrow @nogc:
466     NSObject parent;
467     alias parent this;
468 
469     mixin NSObjectTemplate!(NSDate, "NSDate");
470 
471     static NSDate date()
472     {
473         return NSDate(objc_msgSend(getClassID(), sel!"date"));
474     }
475 
476     static NSTimeInterval timeIntervalSinceReferenceDate()
477     {
478         alias fun_t = extern(C) NSTimeInterval function(id, SEL) nothrow @nogc;
479 
480         version(X86)
481             return (cast(fun_t)objc_msgSend_fpret)(getClassID(), sel!"timeIntervalSinceReferenceDate");
482         else version(X86_64)
483             return (cast(fun_t)objc_msgSend)(getClassID(), sel!"timeIntervalSinceReferenceDate");
484         else
485             return (cast(fun_t)objc_msgSend)(getClassID(), sel!"timeIntervalSinceReferenceDate");
486     }
487 
488     static NSDate dateWithTimeIntervalSinceNow(double secs)
489     {
490         alias fun_t = extern(C) id function(id, SEL, double) nothrow @nogc;
491         id res = (cast(fun_t)objc_msgSend)(getClassID(), sel!"dateWithTimeIntervalSinceNow:", secs);
492 
493         return NSDate(res);
494     }
495 
496     NSString description()
497     {
498         alias fun_t = extern(C) id function(id, SEL) nothrow @nogc;
499         id result = (cast(fun_t)objc_msgSend)(_id, sel!"description");
500 
501         return NSString(result);
502     }
503 
504     NSString descriptionWithLocale()
505     {
506         alias fun_t = extern(C) id function(id, SEL, void*) nothrow @nogc;
507         id result = (cast(fun_t)objc_msgSend)(_id, sel!"descriptionWithLocale:", null);
508         return NSString(result);
509     }
510 }
511 
512 struct NSNumber
513 {
514 nothrow @nogc:
515     NSObject parent;
516     alias parent this;
517 
518     mixin NSObjectTemplate!(NSNumber, "NSNumber");
519 
520     static NSNumber numberWithUnsignedInt(uint value)
521     {
522         alias fun_t = extern(C) id function(id, SEL, uint) nothrow @nogc;
523         id result = (cast(fun_t)objc_msgSend)(getClassID(), sel!"numberWithUnsignedInt:", value);
524 
525         return NSNumber(result);
526     }
527 }