rb-appscript 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +243 -0
- data/LICENSE +1 -0
- data/README +42 -0
- data/TODO +31 -0
- data/doc/aem-manual/01_introduction.html +48 -0
- data/doc/aem-manual/02_apioverview.html +89 -0
- data/doc/aem-manual/03_packingandunpackingdata.html +98 -0
- data/doc/aem-manual/04_references.html +401 -0
- data/doc/aem-manual/05_targettingapplications.html +133 -0
- data/doc/aem-manual/06_buildingandsendingevents.html +175 -0
- data/doc/aem-manual/07_findapp.html +54 -0
- data/doc/aem-manual/08_examples.html +85 -0
- data/doc/aem-manual/09_notes.html +41 -0
- data/doc/aem-manual/aemreferenceinheritance.gif +0 -0
- data/doc/aem-manual/full.css +21 -0
- data/doc/aem-manual/index.html +43 -0
- data/doc/appscript-manual/01_introduction.html +82 -0
- data/doc/appscript-manual/02_aboutappscripting.html +244 -0
- data/doc/appscript-manual/03_quicktutorial.html +154 -0
- data/doc/appscript-manual/04_gettinghelp.html +101 -0
- data/doc/appscript-manual/05_keywordconversion.html +91 -0
- data/doc/appscript-manual/06_classesandenums.html +174 -0
- data/doc/appscript-manual/07_applicationobjects.html +181 -0
- data/doc/appscript-manual/08_realvsgenericreferences.html +86 -0
- data/doc/appscript-manual/09_referenceforms.html +232 -0
- data/doc/appscript-manual/10_referenceexamples.html +142 -0
- data/doc/appscript-manual/11_applicationcommands.html +204 -0
- data/doc/appscript-manual/12_commandexamples.html +129 -0
- data/doc/appscript-manual/13_performanceissues.html +115 -0
- data/doc/appscript-manual/14_problemapps.html +193 -0
- data/doc/appscript-manual/15_notes.html +84 -0
- data/doc/appscript-manual/application_architecture.gif +0 -0
- data/doc/appscript-manual/application_architecture2.gif +0 -0
- data/doc/appscript-manual/finder_to_textedit_event.gif +0 -0
- data/doc/appscript-manual/full.css +21 -0
- data/doc/appscript-manual/index.html +49 -0
- data/doc/appscript-manual/relationships_example.gif +0 -0
- data/doc/appscript-manual/ruby_to_itunes_event.gif +0 -0
- data/doc/index.html +30 -0
- data/doc/mactypes-manual/index.html +216 -0
- data/doc/osax-manual/index.html +169 -0
- data/extconf.rb +54 -0
- data/misc/adobeunittypes.rb +14 -0
- data/misc/dump.rb +72 -0
- data/rb-appscript.gemspec +20 -0
- data/sample/AB_list_people_with_emails.rb +8 -0
- data/sample/Create_daily_iCal_todos.rb +72 -0
- data/sample/Hello_world.rb +9 -0
- data/sample/List_iTunes_playlist_names.rb +7 -0
- data/sample/Make_Mail_message.rb +29 -0
- data/sample/Open_file_in_TextEdit.rb +9 -0
- data/sample/Organize_Mail_messages.rb +57 -0
- data/sample/Print_folder_tree.rb +12 -0
- data/sample/Select_all_HTML_files.rb +8 -0
- data/sample/Set_iChat_status.rb +20 -0
- data/sample/Simple_Finder_GUI_Scripting.rb +14 -0
- data/sample/Stagger_Finder_windows.rb +21 -0
- data/sample/TextEdit_demo.rb +126 -0
- data/sample/iTunes_top40_to_html.rb +64 -0
- data/src/lib/_aem/aemreference.rb +1006 -0
- data/src/lib/_aem/codecs.rb +617 -0
- data/src/lib/_aem/connect.rb +100 -0
- data/src/lib/_aem/findapp.rb +83 -0
- data/src/lib/_aem/mactypes.rb +228 -0
- data/src/lib/_aem/send.rb +257 -0
- data/src/lib/_aem/typewrappers.rb +57 -0
- data/src/lib/_appscript/defaultterminology.rb +245 -0
- data/src/lib/_appscript/referencerenderer.rb +132 -0
- data/src/lib/_appscript/reservedkeywords.rb +107 -0
- data/src/lib/_appscript/terminology.rb +314 -0
- data/src/lib/aem.rb +216 -0
- data/src/lib/appscript.rb +830 -0
- data/src/lib/kae.rb +1484 -0
- data/src/lib/osax.rb +171 -0
- data/src/rbae.c +766 -0
- data/test/README +1 -0
- data/test/test_aemreference.rb +112 -0
- data/test/test_appscriptreference.rb +102 -0
- data/test/test_codecs.rb +159 -0
- data/test/test_findapp.rb +24 -0
- data/test/test_mactypes.rb +67 -0
- data/test/testall.sh +9 -0
- 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, ¶Desc);
|
422
|
+
paraSize = AEGetDescDataSize(¶Desc);
|
423
|
+
paraData = (AppParametersPtr)NewPtr(paraSize);
|
424
|
+
if (paraData == NULL) rbAE_raiseMacOSError("Can't make app parameters AEDesc.", memFullErr);
|
425
|
+
err = AEGetDescData(¶Desc, 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
|
+
}
|