Module: Connect

Defined in:
lib/_aem/connect.rb

Overview

rb-appscript

connect – launch applications and create AEAddressDescs

Defined Under Namespace

Classes: CantLaunchApplicationError

Constant Summary collapse

LSLaunchDefaults =
0x00000001
LSLaunchAndPrint =
0x00000002
LSLaunchReserved2 =
0x00000004
LSLaunchReserved3 =
0x00000008
LSLaunchReserved4 =
0x00000010
LSLaunchReserved5 =
0x00000020
LSLaunchAndDisplayErrors =
0x00000040
LSLaunchInhibitBGOnly =
0x00000080
LSLaunchDontAddToRecents =
0x00000100
LSLaunchDontSwitch =
0x00000200
LSLaunchNoParams =
0x00000800
LSLaunchAsync =
0x00010000
LSLaunchStartClassic =
0x00020000
LSLaunchInClassic =
0x00040000
LSLaunchNewInstance =
0x00080000
LSLaunchAndHide =
0x00100000
LSLaunchAndHideOthers =
0x00200000
LSLaunchHasUntrustedContents =
0x00400000
KNoProcess =
0
KCurrentProcess =
2
NullAddress =
make_address_desc([0,KNoProcess])
LaunchEvent =
Send::Event.new(Connect::NullAddress, 'ascrnoop').AEM_event
RunEvent =
Send::Event.new(Connect::NullAddress, 'aevtoapp').AEM_event
CurrentApp =
make_address_desc([0, KCurrentProcess])
@@encoding_support =
AEMEncodingSupport.encoding_support

Class Method Summary collapse

Class Method Details

.launch_app_with_launch_event(path) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/_aem/connect.rb', line 93

def Connect.launch_app_with_launch_event(path)
  # Send a 'launch' event to an application. If application is not already running, it will be launched in background first.
  path = @@encoding_support.to_utf8_string(path)
  begin
    # If app is already running, calling AE.launch_application will send a 'reopen' event, so need to check for this first:
    psn = AE.psn_for_application_path(path)
  rescue AE::MacOSError => err
    if err.to_i == -600 # Application isn't running, so launch it and send it a 'launch' event
      sleep(1)
      launch_application(path, LaunchEvent)
    else
      raise
    end
  else # App is already running, so send it a 'launch' event
    Send::Event.new(make_address_desc(psn), 'ascrnoop').send(60, KAE::KAENoReply)
  end
end

.launch_application(path, event) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/_aem/connect.rb', line 83

def Connect.launch_application(path, event)
  path = @@encoding_support.to_utf8_string(path)
  begin
    return AE.launch_application(path, event,
                                 LSLaunchNoParams | LSLaunchStartClassic | LSLaunchDontSwitch)
  rescue AE::MacOSError => err
    raise CantLaunchApplicationError, err.to_i
  end
end

.local_app(path) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/_aem/connect.rb', line 170

def Connect.local_app(path)
  # Make an AEAddressDesc identifying a local application. (Application will be launched if not already running.)
  #   path : string -- full path to application, e.g. '/Applications/TextEdit.app'
  #   Result : AEAddressDesc
  #
  # Always creates AEAddressDesc by process serial number; that way there's no confusion if multiple versions of the same app are running.
  path = @@encoding_support.to_utf8_string(path)
  begin
    psn = AE.psn_for_application_path(path)
  rescue AE::MacOSError => err
    if err.to_i == -600 # Application isn't running, so launch it in background and send it a standard 'run' event.
      sleep(1)
      psn = launch_application(path, RunEvent)
    else
      raise
    end
  end
  return make_address_desc(psn)
end

.local_app_by_pid(pid) ⇒ Object



190
191
192
193
194
195
# File 'lib/_aem/connect.rb', line 190

def Connect.local_app_by_pid(pid)
  # Make an AEAddressDesc identifying a running application by Unix process id.
  #   pid : integer -- unsigned 32-bit integer
  #   Result : AEAddressDesc
  return AE::AEDesc.new(KAE::TypeKernelProcessID, [pid].pack('L'))
end

.make_address_desc(psn) ⇒ Object



40
41
42
# File 'lib/_aem/connect.rb', line 40

def Connect.make_address_desc(psn)
  return AE::AEDesc.new(KAE::TypeProcessSerialNumber, psn.pack('LL'))
end

.process_exists_for_desc?(desc) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/_aem/connect.rb', line 150

def Connect.process_exists_for_desc?(desc)
  # Does an application process specified by the given AEAddressDesc exist?
  # Returns false if process doesn't exist OR remote Apple events aren't allowed.
  # Note: this will send a 'launch' Apple event to the target application.
  begin
    # This will usually raise error -1708 if process is running, and various errors
    # if the process doesn't exist/can't be reached. If app is running but busy,
    # AESendMessage may return a timeout error (this should be -1712, but
    # -609 is often returned instead for some reason).
    Send::Event.new(desc, 'ascrnoop').send
  rescue Send::EventError => err
    return (not [-600, -905].include?(err.to_i)) # not running/no network access
  end
  return true
end

.process_exists_for_path?(path) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/_aem/connect.rb', line 113

def Connect.process_exists_for_path?(path)
  path = @@encoding_support.to_utf8_string(path)
  # Does a local process launched from the specified application file exist?
  # Note: if path is invalid, an AE::MacOSError is raised.
  begin
    AE.psn_for_application_path(path)
    return true
  rescue AE::MacOSError => err
    if err.to_i == -600
      return false
    else
      raise
    end
  end
end

.process_exists_for_pid?(pid) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/_aem/connect.rb', line 129

def Connect.process_exists_for_pid?(pid)
  # Is there a local application process with the given unix process id?
  begin
    AE.psn_for_process_id(pid)
    return true
  rescue AE::MacOSError => err
    if err.to_i == -600
      return false
    else
      raise
    end
  end
end

.process_exists_for_url?(url) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


143
144
145
146
147
148
# File 'lib/_aem/connect.rb', line 143

def Connect.process_exists_for_url?(url)
  # Does an application process specified by the given eppc:// URL exist?
  # Note: this will send a 'launch' Apple event to the target application.
  raise ArgumentError, "Invalid url: #{url}" if not url.include?(':') # workaround: process will crash if no colon in URL (OS bug)
  return process_exists_for_desc?(AE::AEDesc.new(KAE::TypeApplicationURL, url))
end

.remote_app(url) ⇒ Object

Raises:

  • (ArgumentError)


197
198
199
200
201
202
203
204
# File 'lib/_aem/connect.rb', line 197

def Connect.remote_app(url)
  url = @@encoding_support.to_utf8_string(url)
  # Make an AEAddressDesc identifying a running application on another machine.
  #   url : string -- URL for remote application, e.g. 'eppc://user:[email protected]/TextEdit'
  #   Result : AEAddressDesc
  raise ArgumentError, "Invalid url: #{url}" if not url.include?(':') # workaround: process will crash if no colon in URL (OS bug)
  return AE::AEDesc.new(KAE::TypeApplicationURL, url)
end