rb-appscript 0.3.0 → 0.4.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.
Files changed (55) hide show
  1. data/CHANGES +45 -0
  2. data/README +5 -1
  3. data/TODO +3 -23
  4. data/doc/aem-manual/04_references.html +6 -6
  5. data/doc/aem-manual/05_targettingapplications.html +3 -3
  6. data/doc/aem-manual/07_findapp.html +1 -1
  7. data/doc/appscript-manual/04_gettinghelp.html +81 -7
  8. data/doc/appscript-manual/05_keywordconversion.html +18 -18
  9. data/doc/appscript-manual/07_applicationobjects.html +4 -4
  10. data/doc/appscript-manual/08_realvsgenericreferences.html +2 -2
  11. data/doc/appscript-manual/09_referenceforms.html +12 -14
  12. data/doc/appscript-manual/11_applicationcommands.html +1 -1
  13. data/doc/appscript-manual/14_notes.html +12 -12
  14. data/doc/osax-manual/index.html +2 -0
  15. data/rb-appscript.gemspec +2 -2
  16. data/sample/AB_list_people_with_emails.rb +3 -0
  17. data/sample/Add_iCal_event.rb +3 -0
  18. data/sample/Create_daily_iCal_todos.rb +2 -0
  19. data/sample/Export_Address_Book_phone_numbers.rb +3 -0
  20. data/sample/Hello_world.rb +3 -0
  21. data/sample/List_iTunes_playlist_names.rb +3 -0
  22. data/sample/Make_Mail_message.rb +3 -0
  23. data/sample/Open_file_in_TextEdit.rb +3 -0
  24. data/sample/Organize_Mail_messages.rb +3 -0
  25. data/sample/Print_folder_tree.rb +3 -0
  26. data/sample/Select_all_HTML_files.rb +3 -0
  27. data/sample/Set_iChat_status.rb +3 -0
  28. data/sample/Simple_Finder_GUI_Scripting.rb +6 -3
  29. data/sample/Stagger_Finder_windows.rb +3 -0
  30. data/sample/TextEdit_demo.rb +3 -0
  31. data/sample/iTunes_top40_to_html.rb +3 -0
  32. data/src/SendThreadSafe.c +380 -0
  33. data/src/SendThreadSafe.h +139 -0
  34. data/src/lib/_aem/aemreference.rb +46 -18
  35. data/src/lib/_aem/codecs.rb +19 -3
  36. data/src/lib/_aem/mactypes.rb +2 -6
  37. data/src/lib/_aem/send.rb +1 -1
  38. data/src/lib/_aem/typewrappers.rb +2 -2
  39. data/src/lib/_appscript/referencerenderer.rb +10 -4
  40. data/src/lib/_appscript/reservedkeywords.rb +4 -4
  41. data/src/lib/_appscript/terminology.rb +43 -35
  42. data/src/lib/aem.rb +8 -4
  43. data/src/lib/appscript.rb +78 -15
  44. data/src/lib/kae.rb +4 -0
  45. data/src/lib/osax.rb +9 -6
  46. data/src/rbae.c +102 -23
  47. data/test/test_aemreference.rb +4 -4
  48. data/test/test_appscriptcommands.rb +2 -2
  49. data/test/test_appscriptreference.rb +4 -4
  50. data/test/test_codecs.rb +14 -1
  51. data/test/test_findapp.rb +1 -1
  52. data/test/test_mactypes.rb +1 -1
  53. data/test/test_osax.rb +1 -1
  54. data/test/testall.sh +1 -1
  55. metadata +4 -2
@@ -28,6 +28,9 @@ ReservedKeywords = [
28
28
  "any",
29
29
  "app",
30
30
  "before",
31
+ "begin_transaction",
32
+ "beginning",
33
+ "begins_with",
31
34
  "by_aem_app",
32
35
  "by_creator",
33
36
  "by_id",
@@ -43,7 +46,7 @@ ReservedKeywords = [
43
46
  "display",
44
47
  "does_not_contain",
45
48
  "does_not_end_with",
46
- "does_not_start_with",
49
+ "does_not_begin_with",
47
50
  "dup",
48
51
  "elements",
49
52
  "end",
@@ -98,9 +101,6 @@ ReservedKeywords = [
98
101
  "result_type",
99
102
  "send",
100
103
  "singleton_methods",
101
- "start",
102
- "start_transaction",
103
- "starts_with",
104
104
  "taint",
105
105
  "tainted?",
106
106
  "timeout",
@@ -8,6 +8,8 @@
8
8
 
9
9
  module TerminologyParser
10
10
 
11
+ require "ae"
12
+ require "kae"
11
13
  require "_appscript/reservedkeywords" # names of all existing methods on ASReference::Application
12
14
 
13
15
  class BigEndianParser
@@ -204,11 +206,10 @@ module TerminologyParser
204
206
 
205
207
  def parse(aetes)
206
208
  aetes.each do |aete|
207
- @_str = aete.data
208
- @_ptr = 6 # version, language, script integers
209
- _integer.times { parse_suite }
210
- if not @_ptr == @_str.length
211
- raise RuntimeError, "aete was not fully parsed."
209
+ if aete.is_a?(AE::AEDesc) and aete.type == KAE::TypeAETE and aete.data != ''
210
+ @_str = aete.data
211
+ @_ptr = 6 # version, language, script integers
212
+ _integer.times { parse_suite }
212
213
  end
213
214
  end
214
215
  # singular names are normally used in the classes table and plural names in the elements table. However, if an aete defines a singular name but not a plural name then the missing plural name is substituted with the singular name; and vice-versa if there's no singular equivalent for a plural name.
@@ -322,7 +323,8 @@ module Terminology
322
323
  def Terminology.tables_for_aetes(aetes)
323
324
  # Build terminology tables from a list of unpacked aete byte strings.
324
325
  # Result : list of hash -- [typebycode, typebyname, referencebycode, referencebyname]
325
- classes, enums, properties, elements, commands = TerminologyParser.build_tables_for_aetes(aetes.delete_if { |aete| not (aete.is_a?(AE::AEDesc) and aete.type == KAE::TypeAETE) })
326
+ aetes = aetes.reject { |aete| not (aete.is_a?(AE::AEDesc) and aete.type == KAE::TypeAETE and aete.data != '') }
327
+ classes, enums, properties, elements, commands = TerminologyParser.build_tables_for_aetes(aetes)
326
328
  return _make_type_table(classes, enums, properties) + _make_reference_table(properties, elements, commands)
327
329
  end
328
330
 
@@ -338,27 +340,30 @@ module Terminology
338
340
  + _make_reference_table(terms::Properties, terms::Elements, terms::Commands)
339
341
  end
340
342
 
343
+ def Terminology.aetes_for_app(aem_app)
344
+ begin
345
+ begin
346
+ aetes = aem_app.event('ascrgdte', {'----' => 0}).send(120 * 60)
347
+ rescue AEM::CommandError => e
348
+ if e.number == -192 # aete resource not found
349
+ aetes = []
350
+ else
351
+ raise
352
+ end
353
+ end
354
+ rescue => err
355
+ raise RuntimeError, "Can't get terminology for application (#{aem_app}): #{err}"
356
+ end
357
+ aetes = [aetes] if not aetes.is_a?(Array)
358
+ return aetes
359
+ end
360
+
341
361
  def Terminology.tables_for_app(aem_app)
342
362
  # Build terminology tables for an application.
343
363
  # app : AEM::Application
344
364
  # Result : list of hash -- [typebycode, typebyname, referencebycode, referencebyname]
345
365
  if not @@_terminology_cache.has_key?(aem_app.identity)
346
- begin
347
- begin
348
- aetes = aem_app.event('ascrgdte', {'----' => 0}).send(60 * 60)
349
- rescue AEM::CommandError => e
350
- if e.number == -192 # aete resource not found
351
- aetes = []
352
- else
353
- raise
354
- end
355
- end
356
- if not aetes.is_a?(Array)
357
- aetes = [aetes]
358
- end
359
- rescue => err
360
- raise RuntimeError, "Can't get terminology for application (#{aem_app}): #{err}"
361
- end
366
+ aetes = Terminology.aetes_for_app(aem_app)
362
367
  @@_terminology_cache[aem_app.identity] = Terminology.tables_for_aetes(aetes)
363
368
  end
364
369
  return @@_terminology_cache[aem_app.identity]
@@ -375,22 +380,25 @@ module Terminology
375
380
  if not /^[A-Z][A-Za-z0-9_]*$/ === module_name
376
381
  raise RuntimeError, "Invalid module name."
377
382
  end
378
- # Write module
379
- File.open(out_path, "w") do |f|
380
- # Get aete(s)
383
+ # Get aete(s)
384
+ begin
381
385
  begin
382
386
  aetes = AEM::Codecs.new.unpack(AE.get_app_terminology(app_path).coerce(KAE::TypeAEList))
383
- rescue AE::MacOSError => e
384
- if e.to_i == -192 # aete resource not found
385
- raise RuntimeError, "No terminology found."
386
- else
387
- raise
388
- end
387
+ rescue NotImplementedError # get_app_terminology is unavailable on 64-bit Leopard
388
+ aetes = Terminology.aetes_for_app(AEM::Application.by_path(app_path))
389
+ end
390
+ rescue AE::MacOSError => e
391
+ if e.to_i == -192 # aete resource not found
392
+ raise RuntimeError, "No terminology found."
393
+ else
394
+ raise
389
395
  end
390
- aetes.delete_if { |aete| not (aete.is_a?(AE::AEDesc) and aete.type == KAE::TypeAETE) }
391
- # Parse aete(s) into intermediate tables, suitable for use by Terminology#tables_for_module
392
- tables = TerminologyParser.build_tables_for_aetes(aetes)
393
- # Write module code
396
+ end
397
+ aetes.delete_if { |aete| not (aete.is_a?(AE::AEDesc) and aete.type == KAE::TypeAETE) }
398
+ # Parse aete(s) into intermediate tables, suitable for use by Terminology#tables_for_module
399
+ tables = TerminologyParser.build_tables_for_aetes(aetes)
400
+ # Write module
401
+ File.open(out_path, "w") do |f|
394
402
  f.puts "module #{module_name}"
395
403
  f.puts "\tVersion = 1.1"
396
404
  f.puts "\tPath = #{app_path.inspect}"
data/src/lib/aem.rb CHANGED
@@ -49,6 +49,10 @@ module AEM
49
49
  return AEMReference::Its
50
50
  end
51
51
 
52
+ def AEM.custom_root(value)
53
+ return AEMReference::CustomRoot.new(value)
54
+ end
55
+
52
56
  #######
53
57
  # Application class
54
58
 
@@ -140,10 +144,10 @@ module AEM
140
144
 
141
145
  def inspect
142
146
  if @identity[0] == :current
143
- return 'AEM::Application.current'
147
+ return "#{self.class}.current"
144
148
  else
145
149
  con_name = {:path => 'by_path', :url => 'by_url', :pid => 'by_pid', :desc => 'by_desc'}[@identity[0]]
146
- return "AEM::Application.#{con_name}(#{@identity[1].inspect})"
150
+ return "#{self.class}.#{con_name}(#{@identity[1].inspect})"
147
151
  end
148
152
  end
149
153
 
@@ -180,8 +184,8 @@ module AEM
180
184
  return self.class::Event.new(@address_desc, event, params, atts, @_transaction, return_id, codecs)
181
185
  end
182
186
 
183
- def start_transaction(session=nil)
184
- # Start a new transaction.
187
+ def begin_transaction(session=nil)
188
+ # Begin a new transaction.
185
189
  if @_transaction != KAE::KAnyTransactionID
186
190
  raise RuntimeError, "Transaction is already active."
187
191
  end
data/src/lib/appscript.rb CHANGED
@@ -11,6 +11,7 @@ module Appscript
11
11
 
12
12
  require "kae"
13
13
  require "aem"
14
+ require "_aem/aemreference"
14
15
  require "_appscript/referencerenderer"
15
16
  require "_appscript/terminology"
16
17
  require "_appscript/safeobject"
@@ -25,6 +26,8 @@ module Appscript
25
26
 
26
27
  class AppData < AEM::Codecs
27
28
 
29
+ HelpAgentID = 'net.sourceforge.appscript.appscripthelpagent'
30
+
28
31
  attr_reader :constructor, :identifier, :reference_codecs
29
32
  attr_writer :reference_codecs
30
33
 
@@ -35,6 +38,7 @@ module Appscript
35
38
  @constructor = constructor # name of AEM::Application constructor to use/:by_aem_app
36
39
  @identifier = identifier # argument for AEM::Application constructor
37
40
  @reference_codecs = AEM::Codecs.new # low-level Codecs object used to unpack references; used by AppData#unpack_object_specifier, AppData#unpack_insertion_loc. Note: this is a bit kludgy, and it's be better to use AppData for all unpacking, but it should be 'good enough' in practice.
41
+ @_help_agent = nil
38
42
  end
39
43
 
40
44
  def connect # initialize AEM::Application instance and terminology tables the first time they are needed
@@ -63,6 +67,54 @@ module Appscript
63
67
 
64
68
  #######
65
69
 
70
+ Constructors = {
71
+ :by_path => 'path',
72
+ :by_pid => 'pid',
73
+ :by_url => 'url',
74
+ :by_aem_app => 'aemapp',
75
+ :current => 'current',
76
+ }
77
+
78
+ def _make_help_agent
79
+ begin
80
+ @_help_agent = AEM::Application.by_path(FindApp.by_id(HelpAgentID))
81
+ return true
82
+ rescue FindApp::ApplicationNotFoundError
83
+ puts "No help available: AppscriptHelpAgent.app not found."
84
+ return false
85
+ end
86
+ end
87
+
88
+ def _display_help(flags, ref)
89
+ begin
90
+ puts @_help_agent.event('ASHAHelp', {
91
+ 'Cons' => Constructors[@constructor],
92
+ 'Iden' => @constructor == :by_aem_app ? @identifier.address_desc : @identifier,
93
+ 'Styl' => 'rb-appscript',
94
+ 'Flag' => flags,
95
+ 'aRef' => pack(ref),
96
+ }).send
97
+ return nil
98
+ rescue AEM::CommandError => e
99
+ return e
100
+ end
101
+ end
102
+
103
+ def help(flags, ref)
104
+ if not @_help_agent
105
+ return ref if not _make_help_agent
106
+ end
107
+ e = _display_help(flags, ref)
108
+ if e and [-600, -609].include?(e.number) # not running
109
+ return ref if not _make_help_agent
110
+ e = _display_help(flags, ref)
111
+ end
112
+ puts "No help available: AppscriptHelpAgent raised an error: #{e}." if e
113
+ return ref
114
+ end
115
+
116
+ #######
117
+
66
118
  def target
67
119
  connect
68
120
  return @target
@@ -309,6 +361,10 @@ module Appscript
309
361
 
310
362
  #######
311
363
 
364
+ def help(flags='-t')
365
+ return @AS_app_data.help(flags, self)
366
+ end
367
+
312
368
  def Reference._pack_uint32(n) # used to pack csig attributes
313
369
  return AE::AEDesc.new(KAE::TypeUInt32, [n].pack('L'))
314
370
  end
@@ -541,13 +597,18 @@ module Appscript
541
597
  new_ref = @AS_aem_reference.by_range(
542
598
  self._resolve_range_boundary(selector, 1),
543
599
  self._resolve_range_boundary(end_range_selector, -1))
544
- elsif selector.is_a?(String)
545
- new_ref = @AS_aem_reference.by_name(selector)
546
- elsif selector.is_a?(Appscript::GenericReference)
547
- new_ref = @AS_aem_reference.by_filter(
548
- selector.AS_resolve(@AS_app_data).AS_aem_reference)
549
600
  else
550
- new_ref = @AS_aem_reference.by_index(selector)
601
+ case selector
602
+ when String
603
+ new_ref = @AS_aem_reference.by_name(selector)
604
+ when Appscript::GenericReference
605
+ new_ref = @AS_aem_reference.by_filter(
606
+ selector.AS_resolve(@AS_app_data).AS_aem_reference)
607
+ when Appscript::Reference, AEMReference::Test
608
+ new_ref = @AS_aem_reference.by_filter(selector)
609
+ else
610
+ new_ref = @AS_aem_reference.by_index(selector)
611
+ end
551
612
  end
552
613
  return Reference.new(@AS_app_data, new_ref)
553
614
  end
@@ -568,8 +629,8 @@ module Appscript
568
629
  return Reference.new(@AS_app_data, @AS_aem_reference.any)
569
630
  end
570
631
 
571
- def start
572
- return Reference.new(@AS_app_data, @AS_aem_reference.start)
632
+ def beginning
633
+ return Reference.new(@AS_app_data, @AS_aem_reference.beginning)
573
634
  end
574
635
 
575
636
  def end
@@ -625,8 +686,8 @@ module Appscript
625
686
  return Reference.new(@AS_app_data, @AS_aem_reference.le(operand))
626
687
  end
627
688
 
628
- def starts_with(operand)
629
- return Reference.new(@AS_app_data, @AS_aem_reference.starts_with(operand))
689
+ def begins_with(operand)
690
+ return Reference.new(@AS_app_data, @AS_aem_reference.begins_with(operand))
630
691
  end
631
692
 
632
693
  def ends_with(operand)
@@ -641,8 +702,8 @@ module Appscript
641
702
  return Reference.new(@AS_app_data, @AS_aem_reference.is_in(operand))
642
703
  end
643
704
 
644
- def does_not_start_with(operand)
645
- return self.starts_with(operand).not
705
+ def does_not_begin_with(operand)
706
+ return self.begins_with(operand).not
646
707
  end
647
708
 
648
709
  def does_not_end_with(operand)
@@ -722,13 +783,15 @@ module Appscript
722
783
  def AS_new_reference(ref)
723
784
  if ref.is_a?(Appscript::GenericReference)
724
785
  return ref.AS_resolve(@AS_app_data)
725
- else
786
+ elsif ref.is_a?(AEMReference::Base)
726
787
  return Reference.new(@AS_app_data, ref)
788
+ else
789
+ return Reference.new(@AS_app_data, AEM.custom_root(ref))
727
790
  end
728
791
  end
729
792
 
730
- def start_transaction(session=nil)
731
- @AS_app_data.target.start_transaction(session)
793
+ def begin_transaction(session=nil)
794
+ @AS_app_data.target.begin_transaction(session)
732
795
  end
733
796
 
734
797
  def abort_transaction
data/src/lib/kae.rb CHANGED
@@ -1481,4 +1481,8 @@ module KAE
1481
1481
  TypeWhoseRange = 'wrng'
1482
1482
  TypeWildCard = '****'
1483
1483
  TypeYards = 'yard'
1484
+
1485
+ # new in 10.5
1486
+ TypeUInt16 = 'ushr'
1487
+ TypeUInt64 = 'ucom'
1484
1488
  end
data/src/lib/osax.rb CHANGED
@@ -5,6 +5,9 @@ require "appscript"
5
5
  module OSAX
6
6
 
7
7
  # Allows scripting additions (a.k.a. OSAXen) to be called from Ruby.
8
+ #
9
+ # Note: currently 32-bit only; attempting to create a new ScriptingAddition instance
10
+ # in a 64-bit process will result in a NotImplementedError.
8
11
 
9
12
  ######################################################################
10
13
  # PRIVATE
@@ -131,13 +134,13 @@ module OSAX
131
134
  if not path
132
135
  raise ArgumentError, "Scripting addition not found: #{name.inspect}"
133
136
  end
134
- if terms
135
- @_terms = terms
136
- else
137
- desc = AE.get_app_terminology(path).coerce(KAE::TypeAEList)
138
- @_terms = OSAXCache[osax_name][1] = \
139
- Terminology.tables_for_aetes(DefaultCodecs.unpack(desc))
137
+ if not terms
138
+ aetes_desc = AE.get_app_terminology(path) # will raise NotImplementedError in 64-bit processes
139
+ aetes = DefaultCodecs.unpack(aetes_desc.coerce(KAE::TypeAEList))
140
+ terms = Terminology.tables_for_aetes(aetes)
141
+ OSAXCache[osax_name][1] = terms
140
142
  end
143
+ @_terms = terms
141
144
  osax_data = OSAXData.new(:current, nil, @_terms)
142
145
  end
143
146
  super(osax_data, AEM.app)
data/src/rbae.c CHANGED
@@ -1,11 +1,15 @@
1
1
  /*
2
2
  * Copyright (C) 2006 HAS
3
3
  *
4
- * Thanks to: FUJIMOTO Hisakuni, author of RubyAEOSA
4
+ * Thanks to:
5
+ * - FUJIMOTO Hisakuni, author of RubyAEOSA
6
+ * - Jordan Breeding (64-bit support patch)
5
7
  */
6
8
 
7
9
  #include "osx_ruby.h"
8
10
  #include <Carbon/Carbon.h>
11
+ #include <CoreFoundation/CoreFoundation.h>
12
+ #include "SendThreadSafe.h"
9
13
 
10
14
  VALUE rb_ll2big(LONG_LONG); // keeps gcc happy
11
15
 
@@ -24,7 +28,11 @@ struct rbAE_AEDescWrapper {
24
28
  #define AEDESC_OF(o) (AEDESC_DATA_PTR(o)->desc)
25
29
 
26
30
  // Event handling
27
- typedef long refcontype;
31
+ #if __LP64__
32
+ // SRefCon typedefed as void * by system headers
33
+ #else
34
+ typedef long SRefCon;
35
+ #endif
28
36
 
29
37
  AEEventHandlerUPP upp_GenericEventHandler;
30
38
  AECoercionHandlerUPP upp_GenericCoercionHandler;
@@ -60,7 +68,7 @@ rbAE_MacOSError_inspect(VALUE self)
60
68
  {
61
69
  char s[32];
62
70
 
63
- sprintf(s, "#<AE::MacOSError %i>", NUM2INT(rb_iv_get(self, "@number")));
71
+ sprintf(s, "#<AE::MacOSError %li>", (long)NUM2INT(rb_iv_get(self, "@number")));
64
72
  return rb_str_new2(s);
65
73
  }
66
74
 
@@ -175,6 +183,19 @@ rbAE_AEDesc_newAppleEvent(VALUE class, VALUE eventClass, VALUE eventID,
175
183
  }
176
184
 
177
185
 
186
+ static VALUE
187
+ rbAE_AEDesc_newUnflatten(VALUE class, VALUE data)
188
+ {
189
+ OSErr err = noErr;
190
+ AEDesc desc;
191
+
192
+ Check_Type(data, T_STRING);
193
+ err = AEUnflattenDesc(RSTRING(data)->ptr, &desc);
194
+ if (err != noErr) rbAE_raiseMacOSError("Can't create AEDesc.", err);
195
+ return rbAE_wrapAEDesc(&desc);
196
+ }
197
+
198
+
178
199
  /**********************************************************************/
179
200
  // AEDesc methods
180
201
 
@@ -225,6 +246,24 @@ rbAE_AEDesc_data(VALUE self)
225
246
  }
226
247
 
227
248
 
249
+ static VALUE
250
+ rbAE_AEDesc_flatten(VALUE self)
251
+ {
252
+ OSErr err = noErr;
253
+ Size dataSize;
254
+ void *data;
255
+ VALUE result;
256
+
257
+ dataSize = AESizeOfFlattenedDesc(&(AEDESC_OF(self)));
258
+ data = malloc(dataSize);
259
+ err = AEFlattenDesc(&(AEDESC_OF(self)), data, dataSize, NULL);
260
+ if (err != noErr) rbAE_raiseMacOSError("Can't flatten AEDesc.", err);
261
+ result = rb_str_new(data, dataSize);
262
+ free(data);
263
+ return result;
264
+ }
265
+
266
+
228
267
  /*******/
229
268
 
230
269
  static VALUE
@@ -328,9 +367,9 @@ rbAE_AEDesc_getParam(VALUE self, VALUE key, VALUE type)
328
367
  AEDesc desc;
329
368
 
330
369
  err = AEGetParamDesc(&(AEDESC_OF(self)),
331
- rbStringToDescType(key),
332
- rbStringToDescType(type),
333
- &desc);
370
+ rbStringToDescType(key),
371
+ rbStringToDescType(type),
372
+ &desc);
334
373
  if (err != noErr) rbAE_raiseMacOSError("Can't get parameter from AEDesc.", err);
335
374
  return rbAE_wrapAEDesc(&desc);
336
375
  }
@@ -343,9 +382,9 @@ rbAE_AEDesc_getAttr(VALUE self, VALUE key, VALUE type)
343
382
  AEDesc desc;
344
383
 
345
384
  err = AEGetAttributeDesc(&(AEDESC_OF(self)),
346
- rbStringToDescType(key),
347
- rbStringToDescType(type),
348
- &desc);
385
+ rbStringToDescType(key),
386
+ rbStringToDescType(type),
387
+ &desc);
349
388
  if (err != noErr) rbAE_raiseMacOSError("Can't get attribute from AEDesc.", err);
350
389
  return rbAE_wrapAEDesc(&desc);
351
390
  }
@@ -367,6 +406,20 @@ rbAE_AEDesc_send(VALUE self, VALUE sendMode, VALUE timeout)
367
406
  return rbAE_wrapAEDesc(&reply);
368
407
  }
369
408
 
409
+ static VALUE
410
+ rbAE_AEDesc_sendThreadSafe(VALUE self, VALUE sendMode, VALUE timeout)
411
+ {
412
+ OSErr err = noErr;
413
+ AppleEvent reply;
414
+
415
+ err = SendMessageThreadSafe(&(AEDESC_OF(self)),
416
+ &reply,
417
+ (AESendMode)NUM2LONG(sendMode),
418
+ NUM2LONG(timeout));
419
+ if (err != noErr) rbAE_raiseMacOSError("Can't send Apple event.", err);
420
+ return rbAE_wrapAEDesc(&reply);
421
+ }
422
+
370
423
 
371
424
  /**********************************************************************/
372
425
  // Find and launch applications
@@ -444,7 +497,9 @@ static VALUE
444
497
  rbAE_launchApplication(VALUE self, VALUE path, VALUE firstEvent, VALUE flags)
445
498
  {
446
499
  FSRef appRef;
447
- FSSpec fss;
500
+ #if !defined(__LP64__)
501
+ FSSpec appFSS;
502
+ #endif
448
503
  AEDesc paraDesc;
449
504
  Size paraSize;
450
505
  AppParametersPtr paraData;
@@ -454,8 +509,10 @@ rbAE_launchApplication(VALUE self, VALUE path, VALUE firstEvent, VALUE flags)
454
509
 
455
510
  err = FSPathMakeRef((UInt8 *)StringValuePtr(path), &appRef, NULL);
456
511
  if (err != 0) rbAE_raiseMacOSError("Couldn't make FSRef for application.", err);
457
- err = FSGetCatalogInfo(&appRef, kFSCatInfoNone, NULL, NULL, &fss, NULL);
512
+ #if !defined(__LP64__)
513
+ err = FSGetCatalogInfo(&appRef, kFSCatInfoNone, NULL, NULL, &appFSS, NULL);
458
514
  if (err != 0) rbAE_raiseMacOSError("Couldn't make FSSpec for application.", err);
515
+ #endif
459
516
  err = AECoerceDesc(&(AEDESC_OF(firstEvent)), typeAppParameters, &paraDesc);
460
517
  paraSize = AEGetDescDataSize(&paraDesc);
461
518
  paraData = (AppParametersPtr)NewPtr(paraSize);
@@ -466,7 +523,11 @@ rbAE_launchApplication(VALUE self, VALUE path, VALUE firstEvent, VALUE flags)
466
523
  launchParams.launchEPBLength = extendedBlockLen;
467
524
  launchParams.launchFileFlags = 0;
468
525
  launchParams.launchControlFlags = (LaunchFlags)NUM2UINT(flags);
469
- launchParams.launchAppSpec = &fss;
526
+ #if defined(__LP64__)
527
+ launchParams.launchAppRef = &appRef;
528
+ #else
529
+ launchParams.launchAppSpec = &appFSS;
530
+ #endif
470
531
  launchParams.launchAppParameters = paraData;
471
532
  err = LaunchApplication(&launchParams);
472
533
  if (err != noErr) rbAE_raiseMacOSError("Can't launch application.", err);
@@ -507,6 +568,10 @@ rbAE_convertUnixSecondsToLongDateTime(VALUE self, VALUE secs)
507
568
  static VALUE
508
569
  rbAE_OSAGetAppTerminology(VALUE self, VALUE path)
509
570
  {
571
+ #if defined(__LP64__)
572
+ rb_raise(rb_eNotImpError, "AE.get_app_terminology isn't available in 64-bit processes.\n");
573
+ return Qnil;
574
+ #else
510
575
  FSRef appRef;
511
576
  FSSpec fss;
512
577
  ComponentInstance defaultComponent;
@@ -514,6 +579,8 @@ rbAE_OSAGetAppTerminology(VALUE self, VALUE path)
514
579
  AEDesc theDesc;
515
580
  OSErr err = noErr;
516
581
 
582
+ if (OSAGetAppTerminology == NULL)
583
+ rb_raise(rb_eNotImpError, "OSAGetAppTerminology unavailable.\n");
517
584
  err = FSPathMakeRef((UInt8 *)StringValuePtr(path), &appRef, NULL);
518
585
  if (err != 0) rbAE_raiseMacOSError("Couldn't make FSRef.", err);
519
586
  err = FSGetCatalogInfo(&appRef, kFSCatInfoNone, NULL, NULL, &fss, NULL);
@@ -529,6 +596,7 @@ rbAE_OSAGetAppTerminology(VALUE self, VALUE path)
529
596
  &theDesc);
530
597
  if (err != 0) rbAE_raiseMacOSError("Couldn't get aete resource.", err);
531
598
  return rbAE_wrapAEDesc(&theDesc);
599
+ #endif
532
600
  }
533
601
 
534
602
 
@@ -540,7 +608,7 @@ rbAE_OSAGetAppTerminology(VALUE self, VALUE path)
540
608
  // TO DO: make sure GC won't collect handler objects while they're installed as event/coercion handlers
541
609
 
542
610
  static pascal OSErr
543
- rbAE_GenericEventHandler(const AppleEvent *request, AppleEvent *reply, refcontype refcon)
611
+ rbAE_GenericEventHandler(const AppleEvent *request, AppleEvent *reply, SRefCon refcon)
544
612
  {
545
613
  VALUE err;
546
614
 
@@ -555,7 +623,7 @@ rbAE_GenericEventHandler(const AppleEvent *request, AppleEvent *reply, refcontyp
555
623
  /*******/
556
624
 
557
625
  static VALUE
558
- rbAE_AEInstallEventHandler(VALUE self, VALUE eventClass, VALUE eventID, VALUE handler)
626
+ rbAE_AEInstallEventHandler(VALUE self, VALUE eventClass, VALUE eventID, SRefCon handler)
559
627
  {
560
628
  /*
561
629
  * eventClass and eventID must be four-character code strings
@@ -569,7 +637,7 @@ rbAE_AEInstallEventHandler(VALUE self, VALUE eventClass, VALUE eventID, VALUE ha
569
637
 
570
638
  err = AEInstallEventHandler(rbStringToDescType(eventClass),
571
639
  rbStringToDescType(eventID),
572
- upp_GenericEventHandler, (long)handler,
640
+ upp_GenericEventHandler, handler,
573
641
  0);
574
642
  if (err != noErr) rbAE_raiseMacOSError("Can't install event handler.", err);
575
643
  return Qnil;
@@ -595,14 +663,14 @@ rbAE_AEGetEventHandler(VALUE self, VALUE eventClass, VALUE eventID)
595
663
  {
596
664
  OSErr err = noErr;
597
665
  AEEventHandlerUPP handlerUPP;
598
- VALUE handler;
666
+ SRefCon handler;
599
667
 
600
668
  err = AEGetEventHandler(rbStringToDescType(eventClass),
601
669
  rbStringToDescType(eventID),
602
- &handlerUPP, (long *)&handler,
670
+ &handlerUPP, &handler,
603
671
  0);
604
672
  if (err != noErr) rbAE_raiseMacOSError("Can't get event handler.", err);
605
- return handler;
673
+ return (VALUE)handler;
606
674
  }
607
675
 
608
676
 
@@ -612,7 +680,7 @@ rbAE_AEGetEventHandler(VALUE self, VALUE eventClass, VALUE eventID)
612
680
  // TO DO: make sure GC won't collect handler objects while they're installed as event/coercion handlers
613
681
 
614
682
  static pascal OSErr
615
- rbAE_GenericCoercionHandler(const AEDesc *fromDesc, DescType toType, refcontype refcon, AEDesc *toDesc)
683
+ rbAE_GenericCoercionHandler(const AEDesc *fromDesc, DescType toType, SRefCon refcon, AEDesc *toDesc)
616
684
  {
617
685
  // handle_coercion method should return an AE::AEDesc, or nil if an error occurred
618
686
  OSErr err = noErr;
@@ -632,7 +700,7 @@ rbAE_GenericCoercionHandler(const AEDesc *fromDesc, DescType toType, refcontype
632
700
  /*******/
633
701
 
634
702
  static VALUE
635
- rbAE_AEInstallCoercionHandler(VALUE self, VALUE fromType, VALUE toType, VALUE handler)
703
+ rbAE_AEInstallCoercionHandler(VALUE self, VALUE fromType, VALUE toType, SRefCon handler)
636
704
  {
637
705
  /*
638
706
  * fromType and toType must be four-character code strings
@@ -647,7 +715,7 @@ rbAE_AEInstallCoercionHandler(VALUE self, VALUE fromType, VALUE toType, VALUE ha
647
715
 
648
716
  err = AEInstallCoercionHandler(rbStringToDescType(fromType),
649
717
  rbStringToDescType(toType),
650
- upp_GenericCoercionHandler, (long)handler,
718
+ upp_GenericCoercionHandler, handler,
651
719
  1, 0);
652
720
  if (err != noErr) rbAE_raiseMacOSError("Can't install coercion handler.", err);
653
721
  return Qnil;
@@ -673,12 +741,12 @@ rbAE_AEGetCoercionHandler(VALUE self, VALUE fromType, VALUE toType)
673
741
  {
674
742
  OSErr err = noErr;
675
743
  AECoercionHandlerUPP handlerUPP;
676
- VALUE handler;
744
+ SRefCon handler;
677
745
  Boolean fromTypeIsDesc;
678
746
 
679
747
  err = AEGetCoercionHandler(rbStringToDescType(fromType),
680
748
  rbStringToDescType(toType),
681
- &handlerUPP, (long *)&handler,
749
+ &handlerUPP, &handler,
682
750
  &fromTypeIsDesc,
683
751
  0);
684
752
  if (err != noErr) rbAE_raiseMacOSError("Can't get coercion handler.", err);
@@ -694,14 +762,22 @@ rbAE_AEGetCoercionHandler(VALUE self, VALUE fromType, VALUE toType)
694
762
  static VALUE
695
763
  rbAE_RunApplicationEventLoop(VALUE self)
696
764
  {
765
+ #if defined(__LP64__)
766
+ rb_raise(rb_eNotImpError, "AE.run_application_event_loop isn't available in 64-bit processes.\n");
767
+ #else
697
768
  RunApplicationEventLoop();
769
+ #endif
698
770
  return Qnil;
699
771
  }
700
772
 
701
773
  static VALUE
702
774
  rbAE_QuitApplicationEventLoop(VALUE self)
703
775
  {
776
+ #if defined(__LP64__)
777
+ rb_raise(rb_eNotImpError, "AE.quit_application_event_loop isn't available in 64-bit processes.\n");
778
+ #else
704
779
  QuitApplicationEventLoop();
780
+ #endif
705
781
  return Qnil;
706
782
  }
707
783
 
@@ -733,11 +809,13 @@ Init_ae (void)
733
809
  rb_define_singleton_method(cAEDesc, "new", rbAE_AEDesc_new, 2);
734
810
  rb_define_singleton_method(cAEDesc, "new_list", rbAE_AEDesc_newList, 1);
735
811
  rb_define_singleton_method(cAEDesc, "new_apple_event", rbAE_AEDesc_newAppleEvent, 5);
812
+ rb_define_singleton_method(cAEDesc, "unflatten", rbAE_AEDesc_newUnflatten, 1);
736
813
 
737
814
  rb_define_method(cAEDesc, "to_s", rbAE_AEDesc_inspect, 0);
738
815
  rb_define_method(cAEDesc, "inspect", rbAE_AEDesc_inspect, 0);
739
816
  rb_define_method(cAEDesc, "type", rbAE_AEDesc_type, 0);
740
817
  rb_define_method(cAEDesc, "data", rbAE_AEDesc_data, 0);
818
+ rb_define_method(cAEDesc, "flatten", rbAE_AEDesc_flatten, 0);
741
819
  rb_define_method(cAEDesc, "is_record?", rbAE_AEDesc_isRecord, 0);
742
820
  rb_define_method(cAEDesc, "coerce", rbAE_AEDesc_coerce, 1);
743
821
  rb_define_method(cAEDesc, "length", rbAE_AEDesc_length, 0);
@@ -748,6 +826,7 @@ Init_ae (void)
748
826
  rb_define_method(cAEDesc, "get_param", rbAE_AEDesc_getParam, 2);
749
827
  rb_define_method(cAEDesc, "get_attr", rbAE_AEDesc_getAttr, 2);
750
828
  rb_define_method(cAEDesc, "send", rbAE_AEDesc_send, 2);
829
+ rb_define_method(cAEDesc, "send_thread_safe", rbAE_AEDesc_sendThreadSafe, 2);
751
830
 
752
831
  // AE::MacOSError
753
832