rb-appscript 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|