rb-appscript 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/CHANGES +243 -0
  2. data/LICENSE +1 -0
  3. data/README +42 -0
  4. data/TODO +31 -0
  5. data/doc/aem-manual/01_introduction.html +48 -0
  6. data/doc/aem-manual/02_apioverview.html +89 -0
  7. data/doc/aem-manual/03_packingandunpackingdata.html +98 -0
  8. data/doc/aem-manual/04_references.html +401 -0
  9. data/doc/aem-manual/05_targettingapplications.html +133 -0
  10. data/doc/aem-manual/06_buildingandsendingevents.html +175 -0
  11. data/doc/aem-manual/07_findapp.html +54 -0
  12. data/doc/aem-manual/08_examples.html +85 -0
  13. data/doc/aem-manual/09_notes.html +41 -0
  14. data/doc/aem-manual/aemreferenceinheritance.gif +0 -0
  15. data/doc/aem-manual/full.css +21 -0
  16. data/doc/aem-manual/index.html +43 -0
  17. data/doc/appscript-manual/01_introduction.html +82 -0
  18. data/doc/appscript-manual/02_aboutappscripting.html +244 -0
  19. data/doc/appscript-manual/03_quicktutorial.html +154 -0
  20. data/doc/appscript-manual/04_gettinghelp.html +101 -0
  21. data/doc/appscript-manual/05_keywordconversion.html +91 -0
  22. data/doc/appscript-manual/06_classesandenums.html +174 -0
  23. data/doc/appscript-manual/07_applicationobjects.html +181 -0
  24. data/doc/appscript-manual/08_realvsgenericreferences.html +86 -0
  25. data/doc/appscript-manual/09_referenceforms.html +232 -0
  26. data/doc/appscript-manual/10_referenceexamples.html +142 -0
  27. data/doc/appscript-manual/11_applicationcommands.html +204 -0
  28. data/doc/appscript-manual/12_commandexamples.html +129 -0
  29. data/doc/appscript-manual/13_performanceissues.html +115 -0
  30. data/doc/appscript-manual/14_problemapps.html +193 -0
  31. data/doc/appscript-manual/15_notes.html +84 -0
  32. data/doc/appscript-manual/application_architecture.gif +0 -0
  33. data/doc/appscript-manual/application_architecture2.gif +0 -0
  34. data/doc/appscript-manual/finder_to_textedit_event.gif +0 -0
  35. data/doc/appscript-manual/full.css +21 -0
  36. data/doc/appscript-manual/index.html +49 -0
  37. data/doc/appscript-manual/relationships_example.gif +0 -0
  38. data/doc/appscript-manual/ruby_to_itunes_event.gif +0 -0
  39. data/doc/index.html +30 -0
  40. data/doc/mactypes-manual/index.html +216 -0
  41. data/doc/osax-manual/index.html +169 -0
  42. data/extconf.rb +54 -0
  43. data/misc/adobeunittypes.rb +14 -0
  44. data/misc/dump.rb +72 -0
  45. data/rb-appscript.gemspec +20 -0
  46. data/sample/AB_list_people_with_emails.rb +8 -0
  47. data/sample/Create_daily_iCal_todos.rb +72 -0
  48. data/sample/Hello_world.rb +9 -0
  49. data/sample/List_iTunes_playlist_names.rb +7 -0
  50. data/sample/Make_Mail_message.rb +29 -0
  51. data/sample/Open_file_in_TextEdit.rb +9 -0
  52. data/sample/Organize_Mail_messages.rb +57 -0
  53. data/sample/Print_folder_tree.rb +12 -0
  54. data/sample/Select_all_HTML_files.rb +8 -0
  55. data/sample/Set_iChat_status.rb +20 -0
  56. data/sample/Simple_Finder_GUI_Scripting.rb +14 -0
  57. data/sample/Stagger_Finder_windows.rb +21 -0
  58. data/sample/TextEdit_demo.rb +126 -0
  59. data/sample/iTunes_top40_to_html.rb +64 -0
  60. data/src/lib/_aem/aemreference.rb +1006 -0
  61. data/src/lib/_aem/codecs.rb +617 -0
  62. data/src/lib/_aem/connect.rb +100 -0
  63. data/src/lib/_aem/findapp.rb +83 -0
  64. data/src/lib/_aem/mactypes.rb +228 -0
  65. data/src/lib/_aem/send.rb +257 -0
  66. data/src/lib/_aem/typewrappers.rb +57 -0
  67. data/src/lib/_appscript/defaultterminology.rb +245 -0
  68. data/src/lib/_appscript/referencerenderer.rb +132 -0
  69. data/src/lib/_appscript/reservedkeywords.rb +107 -0
  70. data/src/lib/_appscript/terminology.rb +314 -0
  71. data/src/lib/aem.rb +216 -0
  72. data/src/lib/appscript.rb +830 -0
  73. data/src/lib/kae.rb +1484 -0
  74. data/src/lib/osax.rb +171 -0
  75. data/src/rbae.c +766 -0
  76. data/test/README +1 -0
  77. data/test/test_aemreference.rb +112 -0
  78. data/test/test_appscriptreference.rb +102 -0
  79. data/test/test_codecs.rb +159 -0
  80. data/test/test_findapp.rb +24 -0
  81. data/test/test_mactypes.rb +67 -0
  82. data/test/testall.sh +9 -0
  83. metadata +143 -0
data/src/rbae.c ADDED
@@ -0,0 +1,766 @@
1
+ /*
2
+ * Copyright (C) 2006 HAS
3
+ *
4
+ * Thanks to: FUJIMOTO Hisakuni, author of RubyAEOSA
5
+ */
6
+
7
+ #include "osx_ruby.h"
8
+ #include <Carbon/Carbon.h>
9
+
10
+ VALUE rb_ll2big(LONG_LONG); // keeps gcc happy
11
+
12
+ // AE module and classes
13
+ static VALUE mAE;
14
+ static VALUE cAEDesc;
15
+ static VALUE cMacOSError;
16
+
17
+ // Note: AEDescs need extra wrapping to avoid nasty problems with Ruby's Data_Wrap_Struct.
18
+ struct rbAE_AEDescWrapper {
19
+ AEDesc desc;
20
+ };
21
+
22
+ // (these two macros are basically cribbed from RubyAEOSA's aedesc.c)
23
+ #define AEDESC_DATA_PTR(o) ((struct rbAE_AEDescWrapper*)(DATA_PTR(o)))
24
+ #define AEDESC_OF(o) (AEDESC_DATA_PTR(o)->desc)
25
+
26
+ // Event handling
27
+ typedef long refcontype;
28
+
29
+ AEEventHandlerUPP upp_GenericEventHandler;
30
+ AECoercionHandlerUPP upp_GenericCoercionHandler;
31
+
32
+
33
+ /**********************************************************************/
34
+ // Raise MacOS error
35
+
36
+ /*
37
+ * Note: MacOSError should only be raised by AE module; attempting to raise it from Ruby
38
+ * just results in unexpected errors. (I've not quite figured out how to implement an
39
+ * Exception class in C that constructs correctly in both C and Ruby. Not serious, since
40
+ * nobody else needs to raise MacOSErrors - just a bit irritating.)
41
+ */
42
+
43
+ static void
44
+ rbAE_raiseMacOSError(const char *description, OSErr number)
45
+ {
46
+ VALUE errObj;
47
+
48
+ errObj = rb_funcall(cMacOSError, rb_intern("new"), 0);
49
+ rb_iv_set(errObj, "@number", INT2NUM(number)); // returns the OS error number
50
+ rb_iv_set(errObj, "@description", rb_str_new2(description)); // troubleshooting info
51
+ rb_exc_raise(errObj);
52
+ }
53
+
54
+
55
+ /**********************************************************************/
56
+ // MacOSError methods
57
+
58
+ static VALUE
59
+ rbAE_MacOSError_inspect(VALUE self)
60
+ {
61
+ char s[32];
62
+
63
+ sprintf(s, "#<AE::MacOSError %i>", NUM2INT(rb_iv_get(self, "@number")));
64
+ return rb_str_new2(s);
65
+ }
66
+
67
+
68
+ /**********************************************************************/
69
+ // AEDesc support functions
70
+
71
+ static DescType
72
+ rbStringToDescType(VALUE obj)
73
+ {
74
+ if (rb_obj_is_kind_of(obj, rb_cString) && RSTRING(obj)->len == 4) {
75
+ return CFSwapInt32HostToBig(*(DescType *)(RSTRING(obj)->ptr));
76
+ } else {
77
+ rb_raise(rb_eArgError, "Not a four-char-code string.");
78
+ }
79
+ }
80
+
81
+ static VALUE
82
+ rbDescTypeToString(DescType descType)
83
+ {
84
+ char s[4];
85
+
86
+ *(DescType*)s = CFSwapInt32HostToBig(descType);
87
+ return rb_str_new(s, 4);
88
+ }
89
+
90
+ /*******/
91
+
92
+ static void
93
+ rbAE_freeAEDesc(struct rbAE_AEDescWrapper *p)
94
+ {
95
+ AEDisposeDesc(&(p->desc));
96
+ free(p);
97
+ }
98
+
99
+ static VALUE
100
+ rbAE_wrapAEDesc(const AEDesc *desc)
101
+ {
102
+ struct rbAE_AEDescWrapper *wrapper;
103
+
104
+ // Found out how to wrap AEDescs so Ruby wouldn't crash by reading RubyAEOSA's aedesc.c
105
+ wrapper = malloc(sizeof(struct rbAE_AEDescWrapper));
106
+ wrapper->desc = *desc;
107
+ return Data_Wrap_Struct(cAEDesc, 0, rbAE_freeAEDesc, wrapper);
108
+ }
109
+
110
+ /*******/
111
+ // Note: clients should not attempt to use retain/use borrowed AE::AEDesc instances after handler callbacks return,
112
+ // as AEM will have disposed of the underlying AEDesc objects by then (TO DO: safety checking in AEDESC_OF?)
113
+
114
+ static void
115
+ rbAE_freeBorrowedAEDesc(struct rbAE_AEDescWrapper *p)
116
+ {
117
+ free(p);
118
+ }
119
+
120
+ static VALUE
121
+ rbAE_wrapBorrowedAEDesc(const AEDesc *desc)
122
+ {
123
+ struct rbAE_AEDescWrapper *wrapper;
124
+
125
+ wrapper = malloc(sizeof(struct rbAE_AEDescWrapper));
126
+ wrapper->desc = *desc;
127
+ return Data_Wrap_Struct(cAEDesc, 0, rbAE_freeBorrowedAEDesc, wrapper);
128
+ }
129
+
130
+ /**********************************************************************/
131
+ // AEDesc constructors
132
+
133
+ static VALUE
134
+ rbAE_AEDesc_new(VALUE class, VALUE type, VALUE data)
135
+ {
136
+ OSErr err = noErr;
137
+ AEDesc desc;
138
+
139
+ Check_Type(data, T_STRING);
140
+ err = AECreateDesc(rbStringToDescType(type),
141
+ RSTRING(data)->ptr, RSTRING(data)->len,
142
+ &desc);
143
+ if (err != noErr) rbAE_raiseMacOSError("Can't create AEDesc.", err);
144
+ return rbAE_wrapAEDesc(&desc);
145
+ }
146
+
147
+
148
+ static VALUE
149
+ rbAE_AEDesc_newList(VALUE class, VALUE isRecord)
150
+ {
151
+ OSErr err = noErr;
152
+ AEDesc desc;
153
+
154
+ err = AECreateList(NULL, 0, RTEST(isRecord), &desc);
155
+ if (err != noErr) rbAE_raiseMacOSError("Can't create AEDescList.", err);
156
+ return rbAE_wrapAEDesc(&desc);
157
+ }
158
+
159
+
160
+ static VALUE
161
+ rbAE_AEDesc_newAppleEvent(VALUE class, VALUE eventClass, VALUE eventID,
162
+ VALUE target, VALUE returnID, VALUE transactionID)
163
+ {
164
+ OSErr err = noErr;
165
+ AEDesc desc;
166
+
167
+ err = AECreateAppleEvent(rbStringToDescType(eventClass),
168
+ rbStringToDescType(eventID),
169
+ &(AEDESC_OF(target)),
170
+ NUM2INT(returnID),
171
+ NUM2LONG(transactionID),
172
+ &desc);
173
+ if (err != noErr) rbAE_raiseMacOSError("Can't create AppleEvent.", err);
174
+ return rbAE_wrapAEDesc(&desc);
175
+ }
176
+
177
+
178
+ /**********************************************************************/
179
+ // AEDesc methods
180
+
181
+ static VALUE
182
+ rbAE_AEDesc_inspect(VALUE self)
183
+ {
184
+ VALUE s, type;
185
+ Size dataSize;
186
+
187
+ s = rb_str_new2("#<AE::AEDesc type=%s size=%i>");
188
+ type = rb_funcall(self, rb_intern("type"), 0);
189
+ dataSize = AEGetDescDataSize(&(AEDESC_OF(self)));
190
+ return rb_funcall(s,
191
+ rb_intern("%"),
192
+ 1,
193
+ rb_ary_new3(2,
194
+ rb_funcall(type, rb_intern("inspect"), 0),
195
+ INT2NUM(dataSize)
196
+ )
197
+ );
198
+ }
199
+
200
+
201
+ /*******/
202
+
203
+ static VALUE
204
+ rbAE_AEDesc_type(VALUE self)
205
+ {
206
+ return rbDescTypeToString(AEDESC_OF(self).descriptorType);
207
+ }
208
+
209
+
210
+ static VALUE
211
+ rbAE_AEDesc_data(VALUE self)
212
+ {
213
+ OSErr err = noErr;
214
+ Size dataSize;
215
+ void *data;
216
+ VALUE result;
217
+
218
+ dataSize = AEGetDescDataSize(&(AEDESC_OF(self)));
219
+ data = malloc(dataSize);
220
+ err = AEGetDescData(&(AEDESC_OF(self)), data, dataSize);
221
+ if (err != noErr) rbAE_raiseMacOSError("Can't get AEDesc data.", err);
222
+ result = rb_str_new(data, dataSize);
223
+ free(data);
224
+ return result;
225
+ }
226
+
227
+
228
+ /*******/
229
+
230
+ static VALUE
231
+ rbAE_AEDesc_isRecord(VALUE self)
232
+ {
233
+ return AECheckIsRecord(&(AEDESC_OF(self))) ? Qtrue : Qfalse;
234
+ }
235
+
236
+ static VALUE
237
+ rbAE_AEDesc_coerce(VALUE self, VALUE type)
238
+ {
239
+ OSErr err = noErr;
240
+ AEDesc desc;
241
+
242
+ err = AECoerceDesc(&(AEDESC_OF(self)), rbStringToDescType(type), &desc);
243
+ if (err != noErr) rbAE_raiseMacOSError("Can't coerce AEDesc.", err);
244
+ return rbAE_wrapAEDesc(&desc);
245
+ }
246
+
247
+ static VALUE
248
+ rbAE_AEDesc_length(VALUE self)
249
+ {
250
+ OSErr err = noErr;
251
+ long length;
252
+
253
+ err = AECountItems(&(AEDESC_OF(self)), &length);
254
+ if (err != noErr) rbAE_raiseMacOSError("Can't get length of AEDesc.", err);
255
+ return INT2NUM(length);
256
+ }
257
+
258
+
259
+ static VALUE
260
+ rbAE_AEDesc_putItem(VALUE self, VALUE index, VALUE desc)
261
+ {
262
+ OSErr err = noErr;
263
+
264
+ if (rb_obj_is_instance_of(desc, cAEDesc) == Qfalse)
265
+ rb_raise(rb_eTypeError, "Can't put non-AEDesc item into AEDesc.");
266
+ err = AEPutDesc(&(AEDESC_OF(self)), NUM2LONG(index), &(AEDESC_OF(desc)));
267
+ if (err != noErr) rbAE_raiseMacOSError("Can't put item into AEDesc.", err);
268
+ return Qnil;
269
+ }
270
+
271
+
272
+ static VALUE
273
+ rbAE_AEDesc_putParam(VALUE self, VALUE key, VALUE desc)
274
+ {
275
+ OSErr err = noErr;
276
+
277
+ if (rb_obj_is_instance_of(desc, cAEDesc) == Qfalse)
278
+ rb_raise(rb_eTypeError, "Can't put non-AEDesc parameter into AEDesc.");
279
+ err = AEPutParamDesc(&(AEDESC_OF(self)), rbStringToDescType(key), &(AEDESC_OF(desc)));
280
+ if (err != noErr) rbAE_raiseMacOSError("Can't put parameter into AEDesc.", err);
281
+ return Qnil;
282
+ }
283
+
284
+
285
+ static VALUE
286
+ rbAE_AEDesc_putAttr(VALUE self, VALUE key, VALUE desc)
287
+ {
288
+ OSErr err = noErr;
289
+
290
+ if (rb_obj_is_instance_of(desc, cAEDesc) == Qfalse)
291
+ rb_raise(rb_eTypeError, "Can't put non-AEDesc attribute into AEDesc.");
292
+ err = AEPutAttributeDesc(&(AEDESC_OF(self)), rbStringToDescType(key), &(AEDESC_OF(desc)));
293
+ if (err != noErr) rbAE_raiseMacOSError("Can't put attribute into AEDesc.", err);
294
+ return Qnil;
295
+ }
296
+
297
+
298
+ static VALUE
299
+ rbAE_AEDesc_get(VALUE self, VALUE index, VALUE type)
300
+ {
301
+ OSErr err = noErr;
302
+ AEKeyword key;
303
+ AEDesc desc;
304
+
305
+ // TO DO: this gives bus error if typeAEList and index = 0 (should be OSErr -1701); why?
306
+ err = AEGetNthDesc(&(AEDESC_OF(self)),
307
+ NUM2LONG(index),
308
+ rbStringToDescType(type),
309
+ &key,
310
+ &desc);
311
+ if (err != noErr) rbAE_raiseMacOSError("Can't get item from AEDesc.", err);
312
+ return rb_ary_new3(2,
313
+ rbDescTypeToString(key),
314
+ rbAE_wrapAEDesc(&desc));
315
+ }
316
+
317
+
318
+ static VALUE
319
+ rbAE_AEDesc_send(VALUE self, VALUE sendMode, VALUE timeout)
320
+ {
321
+ OSErr err = noErr;
322
+ AppleEvent reply;
323
+
324
+ err = AESendMessage(&(AEDESC_OF(self)),
325
+ &reply,
326
+ (AESendMode)NUM2LONG(sendMode),
327
+ NUM2LONG(timeout));
328
+ if (err != noErr) rbAE_raiseMacOSError("Can't send Apple event.", err);
329
+ return rbAE_wrapAEDesc(&reply);
330
+ }
331
+
332
+
333
+ /**********************************************************************/
334
+ // Find and launch applications
335
+
336
+ static VALUE
337
+ rbAE_findApplication(VALUE self, VALUE creator, VALUE bundleID, VALUE name)
338
+ {
339
+ OSStatus err = 0;
340
+
341
+ OSType inCreator;
342
+ CFStringRef inName;
343
+ CFStringRef inBundleID;
344
+ FSRef outAppRef;
345
+ UInt8 path[PATH_MAX];
346
+
347
+ inCreator = (creator == Qnil) ? kLSUnknownCreator : rbStringToDescType(creator);
348
+ if (bundleID != Qnil) {
349
+ inBundleID = CFStringCreateWithBytes(NULL,
350
+ (UInt8 *)(RSTRING(bundleID)->ptr),
351
+ (CFIndex)(RSTRING(bundleID)->len),
352
+ kCFStringEncodingUTF8,
353
+ false);
354
+ if (inBundleID == NULL) rb_raise(rb_eRuntimeError, "Invalid bundle ID string.");
355
+ } else {
356
+ inBundleID = NULL;
357
+ }
358
+ if (name != Qnil) {
359
+ inName = CFStringCreateWithBytes(NULL,
360
+ (UInt8 *)(RSTRING(name)->ptr),
361
+ (CFIndex)(RSTRING(name)->len),
362
+ kCFStringEncodingUTF8,
363
+ false);
364
+ if (inName == NULL) {
365
+ if (inBundleID != NULL) CFRelease(inBundleID);
366
+ rb_raise(rb_eRuntimeError, "Invalid name string.");
367
+ }
368
+ } else {
369
+ inName = NULL;
370
+ }
371
+ err = LSFindApplicationForInfo(inCreator,
372
+ inBundleID,
373
+ inName,
374
+ &outAppRef,
375
+ NULL);
376
+ if (inBundleID != NULL) CFRelease(inBundleID);
377
+ if (inName != NULL) CFRelease(inName);
378
+ if (err != 0) rbAE_raiseMacOSError("Couldn't find application.", err);
379
+ err = FSRefMakePath(&outAppRef, path, PATH_MAX);
380
+ if (err != 0) rbAE_raiseMacOSError("Couldn't get application path.", err);
381
+ return rb_str_new2((char *)path);
382
+ }
383
+
384
+
385
+ static VALUE
386
+ rbAE_psnForApplicationPath(VALUE self, VALUE path)
387
+ {
388
+ OSStatus err = noErr;
389
+ ProcessSerialNumber psn = {0, kNoProcess};
390
+ FSRef appRef, foundRef;
391
+
392
+ err = FSPathMakeRef((UInt8 *)StringValuePtr(path), &appRef, NULL);
393
+ if (err != 0) rbAE_raiseMacOSError("Couldn't make FSRef for application.", err);
394
+ while (1) {
395
+ err = GetNextProcess(&psn);
396
+ if (err != 0) rbAE_raiseMacOSError("Can't get next process.", err); // -600 if no more processes left
397
+ err = GetProcessBundleLocation(&psn, &foundRef);
398
+ if (err != 0) continue;
399
+ if (FSCompareFSRefs(&appRef, &foundRef) == noErr)
400
+ return rb_ary_new3(2, INT2NUM(psn.highLongOfPSN), INT2NUM(psn.lowLongOfPSN));
401
+ }
402
+ }
403
+
404
+
405
+ static VALUE
406
+ rbAE_launchApplication(VALUE self, VALUE path, VALUE firstEvent, VALUE flags)
407
+ {
408
+ FSRef appRef;
409
+ FSSpec fss;
410
+ AEDesc paraDesc;
411
+ Size paraSize;
412
+ AppParametersPtr paraData;
413
+ ProcessSerialNumber psn;
414
+ LaunchParamBlockRec launchParams;
415
+ OSErr err = noErr;
416
+
417
+ err = FSPathMakeRef((UInt8 *)StringValuePtr(path), &appRef, NULL);
418
+ if (err != 0) rbAE_raiseMacOSError("Couldn't make FSRef for application.", err);
419
+ err = FSGetCatalogInfo(&appRef, kFSCatInfoNone, NULL, NULL, &fss, NULL);
420
+ if (err != 0) rbAE_raiseMacOSError("Couldn't make FSSpec for application.", err);
421
+ err = AECoerceDesc(&(AEDESC_OF(firstEvent)), typeAppParameters, &paraDesc);
422
+ paraSize = AEGetDescDataSize(&paraDesc);
423
+ paraData = (AppParametersPtr)NewPtr(paraSize);
424
+ if (paraData == NULL) rbAE_raiseMacOSError("Can't make app parameters AEDesc.", memFullErr);
425
+ err = AEGetDescData(&paraDesc, paraData, paraSize);
426
+ if (err != noErr) rbAE_raiseMacOSError("Can't get AEDesc data.", err);
427
+ launchParams.launchBlockID = extendedBlock;
428
+ launchParams.launchEPBLength = extendedBlockLen;
429
+ launchParams.launchFileFlags = 0;
430
+ launchParams.launchControlFlags = (LaunchFlags)NUM2UINT(flags);
431
+ launchParams.launchAppSpec = &fss;
432
+ launchParams.launchAppParameters = paraData;
433
+ err = LaunchApplication(&launchParams);
434
+ if (err != noErr) rbAE_raiseMacOSError("Can't launch application.", err);
435
+ psn = launchParams.launchProcessSN;
436
+ return rb_ary_new3(2, INT2NUM(psn.highLongOfPSN), INT2NUM(psn.lowLongOfPSN));
437
+ }
438
+
439
+ static VALUE
440
+ rbAE_pidToPsn(VALUE self, VALUE pid) // TO DO: not currently used by aem/appscript; delete?
441
+ {
442
+ OSStatus err = 0;
443
+ ProcessSerialNumber psn;
444
+
445
+ err = GetProcessForPID((pid_t)NUM2INT(pid), &psn);
446
+ if (err != noErr) rbAE_raiseMacOSError("Can't convert PID to PSN.", err);
447
+ return rb_ary_new3(2, INT2NUM(psn.highLongOfPSN), INT2NUM(psn.lowLongOfPSN));
448
+ }
449
+
450
+ /**********************************************************************/
451
+ // Date conversion
452
+
453
+ static VALUE
454
+ rbAE_convertLongDateTimeToUnixSeconds(VALUE self, VALUE ldt)
455
+ {
456
+ OSStatus err = 0;
457
+ CFAbsoluteTime cfTime;
458
+
459
+ err = UCConvertLongDateTimeToCFAbsoluteTime(rb_big2ll(ldt), &cfTime);
460
+ if (err != noErr) rbAE_raiseMacOSError("Can't convert LongDateTime to seconds.", err);
461
+ return rb_float_new(cfTime + kCFAbsoluteTimeIntervalSince1970);
462
+ }
463
+
464
+
465
+ static VALUE
466
+ rbAE_convertUnixSecondsToLongDateTime(VALUE self, VALUE secs)
467
+ {
468
+ OSStatus err = 0;
469
+ SInt64 ldt;
470
+
471
+ err = UCConvertCFAbsoluteTimeToLongDateTime(NUM2DBL(secs) - kCFAbsoluteTimeIntervalSince1970, &ldt);
472
+ if (err != noErr) rbAE_raiseMacOSError("Can't convert seconds to LongDateTime.", err);
473
+ return rb_ll2big(ldt);
474
+ }
475
+
476
+
477
+ /**********************************************************************/
478
+ // Get aete
479
+
480
+ static VALUE
481
+ rbAE_OSAGetAppTerminology(VALUE self, VALUE path)
482
+ {
483
+ FSRef appRef;
484
+ FSSpec fss;
485
+ ComponentInstance defaultComponent;
486
+ Boolean didLaunch;
487
+ AEDesc theDesc;
488
+ OSErr err = noErr;
489
+
490
+ err = FSPathMakeRef((UInt8 *)StringValuePtr(path), &appRef, NULL);
491
+ if (err != 0) rbAE_raiseMacOSError("Couldn't make FSRef.", err);
492
+ err = FSGetCatalogInfo(&appRef, kFSCatInfoNone, NULL, NULL, &fss, NULL);
493
+ if (err != 0) rbAE_raiseMacOSError("Couldn't make FSSpec.", err);
494
+ defaultComponent = OpenDefaultComponent(kOSAComponentType, 'ascr');
495
+ err = GetComponentInstanceError(defaultComponent);
496
+ if (err != 0) rbAE_raiseMacOSError("Couldn't make default component instance.", err);
497
+ err = OSAGetAppTerminology(defaultComponent,
498
+ kOSAModeNull,
499
+ &fss,
500
+ 0,
501
+ &didLaunch,
502
+ &theDesc);
503
+ if (err != 0) rbAE_raiseMacOSError("Couldn't get aete resource.", err);
504
+ return rbAE_wrapAEDesc(&theDesc);
505
+ }
506
+
507
+
508
+ /**********************************************************************/
509
+ // Install event handlers
510
+
511
+ // Based on Python's CarbonX.AE extension
512
+
513
+ // TO DO: make sure GC won't collect handler objects while they're installed as event/coercion handlers
514
+
515
+ static pascal OSErr
516
+ rbAE_GenericEventHandler(const AppleEvent *request, AppleEvent *reply, refcontype refcon)
517
+ {
518
+ VALUE err;
519
+
520
+ err = rb_funcall((VALUE)refcon,
521
+ rb_intern("handle_event"),
522
+ 2,
523
+ rbAE_wrapBorrowedAEDesc(request),
524
+ rbAE_wrapBorrowedAEDesc(reply));
525
+ return NUM2INT(err);
526
+ }
527
+
528
+ /*******/
529
+
530
+ static VALUE
531
+ rbAE_AEInstallEventHandler(VALUE self, VALUE eventClass, VALUE eventID, VALUE handler)
532
+ {
533
+ /*
534
+ * eventClass and eventID must be four-character code strings
535
+ *
536
+ * handler must be a Ruby object containing a method named 'handle_event' that takes two
537
+ * AppleEvent descriptors (request and reply) as arguments, and returns an integer.
538
+ * Note that this object is responsible for trapping any unhandled exceptions and returning
539
+ * an OS error number as appropriate (or 0 if no error), otherwise the program will exit.
540
+ */
541
+ OSErr err = noErr;
542
+
543
+ err = AEInstallEventHandler(rbStringToDescType(eventClass),
544
+ rbStringToDescType(eventID),
545
+ upp_GenericEventHandler, (long)handler,
546
+ 0);
547
+ if (err != noErr) rbAE_raiseMacOSError("Can't install event handler.", err);
548
+ return Qnil;
549
+ }
550
+
551
+
552
+ static VALUE
553
+ rbAE_AERemoveEventHandler(VALUE self, VALUE eventClass, VALUE eventID)
554
+ {
555
+ OSErr err = noErr;
556
+
557
+ err = AERemoveEventHandler(rbStringToDescType(eventClass),
558
+ rbStringToDescType(eventID),
559
+ upp_GenericEventHandler,
560
+ 0);
561
+ if (err != noErr) rbAE_raiseMacOSError("Can't remove event handler.", err);
562
+ return Qnil;
563
+ }
564
+
565
+
566
+ static VALUE
567
+ rbAE_AEGetEventHandler(VALUE self, VALUE eventClass, VALUE eventID)
568
+ {
569
+ OSErr err = noErr;
570
+ AEEventHandlerUPP handlerUPP;
571
+ VALUE handler;
572
+
573
+ err = AEGetEventHandler(rbStringToDescType(eventClass),
574
+ rbStringToDescType(eventID),
575
+ &handlerUPP, (long *)&handler,
576
+ 0);
577
+ if (err != noErr) rbAE_raiseMacOSError("Can't get event handler.", err);
578
+ return handler;
579
+ }
580
+
581
+
582
+ /**********************************************************************/
583
+ // Install coercion handlers
584
+
585
+ // TO DO: make sure GC won't collect handler objects while they're installed as event/coercion handlers
586
+
587
+ static pascal OSErr
588
+ rbAE_GenericCoercionHandler(const AEDesc *fromDesc, DescType toType, refcontype refcon, AEDesc *toDesc)
589
+ {
590
+ // handle_coercion method should return an AE::AEDesc, or nil if an error occurred
591
+ OSErr err = noErr;
592
+ VALUE res;
593
+
594
+ res = rb_funcall((VALUE)refcon,
595
+ rb_intern("handle_coercion"),
596
+ 2,
597
+ rbAE_wrapBorrowedAEDesc(fromDesc),
598
+ rbDescTypeToString(toType));
599
+ if (rb_obj_is_instance_of(res, cAEDesc) != Qtrue) return errAECoercionFail;
600
+ err = AEDuplicateDesc(&AEDESC_OF(res), toDesc);
601
+ return err;
602
+ }
603
+
604
+
605
+ /*******/
606
+
607
+ static VALUE
608
+ rbAE_AEInstallCoercionHandler(VALUE self, VALUE fromType, VALUE toType, VALUE handler)
609
+ {
610
+ /*
611
+ * fromType and toType must be four-character code strings
612
+ *
613
+ * handler must be a Ruby object containing a method named 'handle_coercion' that takes an
614
+ * AEDesc and a four-character code (original value, desired type) as arguments, and returns an
615
+ * AEDesc of the desired type.Note that this object is responsible for trapping any unhandled
616
+ * exceptions and returning nil (or any other non-AEDesc value) as appropriate, otherwise the
617
+ * program will exit.
618
+ */
619
+ OSErr err = noErr;
620
+
621
+ err = AEInstallCoercionHandler(rbStringToDescType(fromType),
622
+ rbStringToDescType(toType),
623
+ upp_GenericCoercionHandler, (long)handler,
624
+ 1, 0);
625
+ if (err != noErr) rbAE_raiseMacOSError("Can't install coercion handler.", err);
626
+ return Qnil;
627
+ }
628
+
629
+
630
+ static VALUE
631
+ rbAE_AERemoveCoercionHandler(VALUE self, VALUE fromType, VALUE toType)
632
+ {
633
+ OSErr err = noErr;
634
+
635
+ err = AERemoveCoercionHandler(rbStringToDescType(fromType),
636
+ rbStringToDescType(toType),
637
+ upp_GenericCoercionHandler,
638
+ 0);
639
+ if (err != noErr) rbAE_raiseMacOSError("Can't remove coercion handler.", err);
640
+ return Qnil;
641
+ }
642
+
643
+
644
+ static VALUE
645
+ rbAE_AEGetCoercionHandler(VALUE self, VALUE fromType, VALUE toType)
646
+ {
647
+ OSErr err = noErr;
648
+ AECoercionHandlerUPP handlerUPP;
649
+ VALUE handler;
650
+ Boolean fromTypeIsDesc;
651
+
652
+ err = AEGetCoercionHandler(rbStringToDescType(fromType),
653
+ rbStringToDescType(toType),
654
+ &handlerUPP, (long *)&handler,
655
+ &fromTypeIsDesc,
656
+ 0);
657
+ if (err != noErr) rbAE_raiseMacOSError("Can't get coercion handler.", err);
658
+ return rb_ary_new3(2, handler, fromTypeIsDesc ? Qtrue : Qfalse);
659
+ }
660
+
661
+
662
+
663
+
664
+ /**********************************************************************/
665
+ // Process management
666
+
667
+ static VALUE
668
+ rbAE_RunApplicationEventLoop(VALUE self)
669
+ {
670
+ RunApplicationEventLoop();
671
+ return Qnil;
672
+ }
673
+
674
+ static VALUE
675
+ rbAE_QuitApplicationEventLoop(VALUE self)
676
+ {
677
+ QuitApplicationEventLoop();
678
+ return Qnil;
679
+ }
680
+
681
+ static VALUE
682
+ rbAE_transformProcessToForegroundApplication(VALUE self)
683
+ {
684
+ OSStatus err = 0;
685
+ ProcessSerialNumber psn = {0, kCurrentProcess};
686
+
687
+ err = TransformProcessType(& psn, kProcessTransformToForegroundApplication);
688
+ if( err != 0) rbAE_raiseMacOSError("Can't transform process.", err);
689
+ return Qnil;
690
+ }
691
+
692
+
693
+ /**********************************************************************/
694
+ // Initialisation
695
+
696
+ void
697
+ Init_ae (void)
698
+ {
699
+
700
+ mAE = rb_define_module("AE");
701
+
702
+ // AE::AEDesc
703
+
704
+ cAEDesc = rb_define_class_under(mAE, "AEDesc", rb_cObject);
705
+
706
+ rb_define_singleton_method(cAEDesc, "new", rbAE_AEDesc_new, 2);
707
+ rb_define_singleton_method(cAEDesc, "new_list", rbAE_AEDesc_newList, 1);
708
+ rb_define_singleton_method(cAEDesc, "new_apple_event", rbAE_AEDesc_newAppleEvent, 5);
709
+
710
+ rb_define_method(cAEDesc, "to_s", rbAE_AEDesc_inspect, 0);
711
+ rb_define_method(cAEDesc, "inspect", rbAE_AEDesc_inspect, 0);
712
+ rb_define_method(cAEDesc, "type", rbAE_AEDesc_type, 0);
713
+ rb_define_method(cAEDesc, "data", rbAE_AEDesc_data, 0);
714
+ rb_define_method(cAEDesc, "is_record?", rbAE_AEDesc_isRecord, 0);
715
+ rb_define_method(cAEDesc, "coerce", rbAE_AEDesc_coerce, 1);
716
+ rb_define_method(cAEDesc, "length", rbAE_AEDesc_length, 0);
717
+ rb_define_method(cAEDesc, "put_item", rbAE_AEDesc_putItem, 2);
718
+ rb_define_method(cAEDesc, "put_param", rbAE_AEDesc_putParam, 2);
719
+ rb_define_method(cAEDesc, "put_attr", rbAE_AEDesc_putAttr, 2);
720
+ rb_define_method(cAEDesc, "get", rbAE_AEDesc_get, 2);
721
+ rb_define_method(cAEDesc, "send", rbAE_AEDesc_send, 2);
722
+
723
+ // AE::MacOSError
724
+
725
+ cMacOSError = rb_define_class_under(mAE, "MacOSError", rb_eStandardError);
726
+
727
+ rb_define_attr(cMacOSError, "number", Qtrue, Qfalse);
728
+ rb_define_attr(cMacOSError, "description", Qtrue, Qfalse);
729
+
730
+ rb_define_alias(cMacOSError, "to_i", "number");
731
+
732
+ rb_define_method(cMacOSError, "to_s", rbAE_MacOSError_inspect, 0);
733
+ rb_define_method(cMacOSError, "inspect", rbAE_MacOSError_inspect, 0);
734
+
735
+ // Support functions
736
+
737
+ rb_define_module_function(mAE, "find_application", rbAE_findApplication, 3);
738
+ rb_define_module_function(mAE, "psn_for_application_path", rbAE_psnForApplicationPath, 1);
739
+ rb_define_module_function(mAE, "launch_application", rbAE_launchApplication, 3);
740
+ rb_define_module_function(mAE, "pid_to_psn", rbAE_pidToPsn, 1);
741
+
742
+ rb_define_module_function(mAE, "convert_long_date_time_to_unix_seconds",
743
+ rbAE_convertLongDateTimeToUnixSeconds, 1);
744
+ rb_define_module_function(mAE, "convert_unix_seconds_to_long_date_time",
745
+ rbAE_convertUnixSecondsToLongDateTime, 1);
746
+
747
+ rb_define_module_function(mAE, "get_app_terminology", rbAE_OSAGetAppTerminology, 1);
748
+
749
+ // Event handling
750
+
751
+ upp_GenericEventHandler = NewAEEventHandlerUPP(rbAE_GenericEventHandler);
752
+ upp_GenericCoercionHandler = NewAECoerceDescUPP(rbAE_GenericCoercionHandler);
753
+
754
+ rb_define_module_function(mAE, "install_event_handler", rbAE_AEInstallEventHandler, 3);
755
+ rb_define_module_function(mAE, "remove_event_handler", rbAE_AERemoveEventHandler, 2);
756
+ rb_define_module_function(mAE, "get_event_handler", rbAE_AEGetEventHandler, 2);
757
+
758
+ rb_define_module_function(mAE, "install_coercion_handler", rbAE_AEInstallCoercionHandler, 3);
759
+ rb_define_module_function(mAE, "remove_coercion_handler", rbAE_AERemoveCoercionHandler, 2);
760
+ rb_define_module_function(mAE, "get_coercion_handler", rbAE_AEGetCoercionHandler, 2);
761
+
762
+ rb_define_module_function(mAE, "run_application_event_loop", rbAE_RunApplicationEventLoop, 0);
763
+ rb_define_module_function(mAE, "quit_application_event_loop", rbAE_QuitApplicationEventLoop, 0);
764
+ rb_define_module_function(mAE, "transform_process_to_foreground_application",
765
+ rbAE_transformProcessToForegroundApplication, 0);
766
+ }