class AX::Application
The accessibility object representing the running application. This class contains some additional constructors and conveniences for Application
objects.
As this class has evolved, it has gathered some functionality from the ‘NSRunningApplication` and `NSBundle` classes.
Public Class Methods
Find and return the dock application
@return [AX::Application]
# File lib/ax/application.rb, line 31 def dock new 'com.apple.dock' end
Find and return the dock application
@return [AX::Application]
# File lib/ax/application.rb, line 39 def finder new 'com.apple.finder' end
Find and return the application which is frontmost
This is often, but not necessarily, the same as the app that owns the menu bar.
@return [AX::Application]
# File lib/ax/application.rb, line 60 def frontmost_application new NSWorkspace.sharedWorkspace.frontmostApplication end
Asynchronously launch an application with given the bundle identifier
@param bundle [String] bundle identifier for the app @return [Boolean]
# File lib/ax/application.rb, line 20 def launch bundle NSWorkspace.sharedWorkspace.launchAppWithBundleIdentifier bundle, options: NSWorkspace::NSWorkspaceLaunchAsync, additionalEventParamDescriptor: nil, launchIdentifier: nil end
@note Initialization with bundle identifiers is case-sensitive
(e.g. 'com.apple.iCal' is correct, 'com.apple.ical' is wrong)
Standard way of creating a new application object
You can initialize an application object with either the process identifier (pid) of the application, the name of the application, the bundle identifier string (e.g. ‘com.company.appName’), an ‘NSRunningApplication` instance for the application, or an accessibility (`AXUIElementRef`) token.
Given a PID, we try to lookup the application and wrap it.
Given an ‘NSRunningApplication` instance, we simply wrap it.
Given a string we do some complicated magic to try and figure out if the string is a bundle identifier or the localized name of the application. Given a bundle identifier we try to launch the app if it is not already running, given a localized name we search the running applications for the app. We wrap what we get back if we get anything back.
Note however, given a bundle identifier to launch the application our implementation is a bit of a hack; I’ve tried to register for notifications, launch synchronously, etc., but there is always a problem with accessibility not being ready right away, so we will poll the app to see when it is ready with a timeout of ~10 seconds.
If this method fails to find an app then an exception will be raised.
@example
AX::Application.new 'com.apple.mail' AX::Application.new 'Mail' AX::Application.new 578 AX::Application.new 'com.apple.iCal' AX::Application.new 'Calendar' AX::Application.new 3782 AX::Application.new 'com.apple.AddressBook' AX::Application.new 'Contacts' AX::Application.new 43567
@param arg [Number,String,NSRunningApplication]
AX::Element::new
# File lib/ax/application.rb, line 121 def initialize arg @app = case arg when String init_with_bundle_id(arg) || init_with_name(arg) || try_launch(arg) when Fixnum NSRunningApplication.runningApplicationWithProcessIdentifier arg when NSRunningApplication arg else # assume it is an AXUIElementRef (Accessibility::Element) NSRunningApplication.runningApplicationWithProcessIdentifier arg.pid end super Accessibility::Element.application_for @app.processIdentifier end
Find and return the notification center UI app
Obviously, this will only work on OS X 10.8+
@return [AX::Application]
# File lib/ax/application.rb, line 49 def notification_center new 'com.apple.notificationcenterui' end
Public Instance Methods
Ask the app whether or not it is the active app. This is equivalent to the dynamic ‘#focused?` method, but might make more sense to use in some cases.
# File lib/ax/application.rb, line 159 def active? spin @app.active? end
(see AX::Element#attribute
)
AX::Element#attribute
# File lib/ax/application.rb, line 139 def attribute attr case attr when :focused?, :focused then active? when :hidden?, :hidden then hidden? else super end end
Get the bundle identifier for the application.
@example
safari.bundle_identifier 'com.apple.safari' daylite.bundle_identifier 'com.marketcircle.Daylite'
@return [String]
# File lib/ax/application.rb, line 201 def bundle_identifier @app.bundleIdentifier end
Find the element in the receiver that is at point given.
‘nil` will be returned if there was nothing at that point.
@param point [#to_point] @return [AX::Element,nil]
# File lib/ax/application.rb, line 416 def element_at point @ref.element_at(point).to_ruby end
@note This is often async and may return before the action is completed
Ask the app to hide itself
@return [Boolean]
# File lib/ax/application.rb, line 261 def hide perform :hide end
Press the given modifier key and hold it down while yielding to the given block. As with {#type}, the key events apply to the control element which is currently focused.
@example
hold_modifier "\\CONTROL" do drag_mouse_to point end
@param key [String] @return [Number,nil]
# File lib/ax/application.rb, line 326 def hold_modifier key code = EventGenerator::CUSTOM[key] raise ArgumentError, "Invalid modifier `#{key}' given" unless code KeyCoder.post_event([code, true]) yield ensure KeyCoder.post_event([code, false]) if code code end
Return the ‘Info.plist` data for the application. This is a plist file that all bundles in OS X must contain.
Many bits of metadata are stored in the plist, check the [reference](developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigFiles.html) for more details.
@return [Hash]
# File lib/ax/application.rb, line 214 def info_plist bundle.infoDictionary end
Override the base class to make sure the pid is included.
AX::Element#inspect
# File lib/ax/application.rb, line 405 def inspect super.sub! />$/, "#{pp_checkbox(:focused)} pid=#{pid}>" end
@see AX::Element#perform
AX::Element#perform
# File lib/ax/application.rb, line 276 def perform name case name when :terminate return true if terminated? @app.terminate; spin 0.25; terminated? when :force_terminate return true if terminated? @app.forceTerminate; spin 0.25; terminated? when :hide return true if hidden? @app.hide; spin 0.25; hidden? when :unhide return true if active? @app.activateWithOptions(NSRunningApplication::NSApplicationActivateIgnoringOtherApps) spin 0.25; active? else super end end
(see AX::Element#set
)
AX::Element#set
# File lib/ax/application.rb, line 181 def set attr, value case attr when :focused perform(value ? :unhide : :hide) when :active, :hidden perform(value ? :hide : :unhide) else super end end
Show the “About” window for the app. Returns the window that is opened.
@return [AX::Window]
# File lib/ax/application.rb, line 380 def show_about_window windows = self.children.select { |x| x.kind_of? AX::Window } select_menu_item self.title, /^About / wait_for(:window, parent: self) { |window| !windows.include?(window) } end
@note This method assumes that the app has setup the standard
CMD+, hotkey to open the pref window
Try to open the preferences for the app. Returns the window that is opened.
@return [AX::Window]
# File lib/ax/application.rb, line 394 def show_preferences_window windows = self.children.select { |x| x.kind_of? AX::Window } type "\\COMMAND+," wait_for(:window, parent: self) { |window| !windows.include?(window) } end
@note This is often async and may return before the action is completed
Ask the app to quit
@return [Boolean]
# File lib/ax/application.rb, line 241 def terminate perform :terminate end
@note This is often async and may return before the action is completed
Force the app to quit
@return [Boolean]
# File lib/ax/application.rb, line 251 def terminate! perform :force_terminate end
Ask the app whether or not it is still running.
# File lib/ax/application.rb, line 175 def terminated? spin @app.terminated? end
Send keyboard input to the focused control element; this is not necessarily an element belonging to the receiving app.
For details on how to format the string, check out the [Keyboarding documentation](github.com/Marketcircle/AXElements/wiki/Keyboarding).
@param string [String] @return [Boolean]
# File lib/ax/application.rb, line 305 def type string perform(:unhide) unless focused? keyboard_events_for(string).each do |event| KeyCoder.post_event event end end
@note This is often async and may return before the action is completed
As the app to unhide itself and bring to front
@return [Boolean]
# File lib/ax/application.rb, line 271 def unhide perform :unhide end
Get the version string for the application.
@example
AX::Application.new("Safari").version # => "5.2" AX::Application.new("Terminal").version # => "2.2.2" AX::Application.new("Daylite").version # => "3.15 (build 3664)"
@return [String]
# File lib/ax/application.rb, line 228 def version bundle.objectForInfoDictionaryKey 'CFBundleShortVersionString' end
(see AX::Element#writable?
)
AX::Element#writable?
# File lib/ax/application.rb, line 148 def writable? attr case attr when :focused?, :focused, :hidden?, :hidden then true else super end end
Private Instance Methods
@return [NSBundle]
# File lib/ax/application.rb, line 424 def bundle @bundle ||= NSBundle.bundleWithURL @app.bundleURL end
# File lib/ax/application.rb, line 428 def init_with_bundle_id id app = NSRunningApplication.runningApplicationsWithBundleIdentifier id app.first end
# File lib/ax/application.rb, line 433 def init_with_name name spin NSWorkspace.sharedWorkspace.runningApplications.find { |app| app.localizedName == name } end
# File lib/ax/application.rb, line 440 def try_launch id 10.times do app = init_with_bundle_id id return app if app if AX::Application.launch id spin 1 else raise "#{id} is not a registered bundle identifier for the system" end end raise "#{id} failed to launch in time" end