Permalink
Browse files

Put Notification class/module stuff directly in AX::Element

The abstraction of having it in its own module seems strange, this is easier, though
it does the make the element.rb file that much larger… :/
  • Loading branch information...
1 parent 71d7c34 commit fe98f435d389af138592f30a1aaabf90a49cc1c4 @ferrous26 ferrous26 committed Feb 18, 2012
Showing with 69 additions and 91 deletions.
  1. +0 −78 lib/accessibility/notification.rb
  2. +69 −13 lib/ax/element.rb
@@ -1,78 +0,0 @@
-##
-# A convenient wrapper around {Accessibility::Core} notification methods.
-#
-# It is expected that you will mix this in to a class that also has had
-# {Accessibility::Core} or equivalent methods implemented.
-module Accessibility::Notification
-
- ##
- # Register to receive notification of the given event being completed
- # by the given element.
- #
- # {file:docs/Notifications.markdown Notifications} are a way to put
- # non-polling delays into your scripts.
- #
- # Use this method to register to be notified of the specified event in
- # an application. You must also pass a block to this method to validate
- # the notification.
- #
- # @example
- #
- # register_to_receive(KAXWindowCreatedNotification, from: safari) { |notif, element|
- # puts "#{element.description} sent #{notif.inspect}"
- # true
- # }
- #
- # @param [String] notif the name of the notification
- # @param [AXUIElementRef] element the element which will send the notification
- # @yield Validate the notification; the block should return truthy if
- # the notification received is the expected one and the script can stop
- # waiting, otherwise should return falsy.
- # @yieldparam [String] notif the name of the notification
- # @yieldparam [AXUIElementRef] element the element that sent the notification
- # @yieldreturn [Boolean] determines if the script should continue or wait
- # @return [Array(Observer, String, AXUIElementRef)] the registration triple
- def register notif, &block
- callback = create_callback_for block
- observer = observer_for @ref, &callback
- source = run_loop_source_for observer
- register observer, to_receive: notif, for: @ref
- @notifs[notif] = [observer, source]
- end
-
- # @todo What are the implications of not removing the run loop source?
- # Taking it out would clobber other notifications that are using
- # the same source, so we would have to check if we can remove it.
- #
- def unregister notif
- unless @notifs.has_key? notif
- raise ArgumentError, "You have no registrations for #{notif}"
- end
- observer, source = @notifs.delete notif
- unregister observer, from_receiving: notif, for: @ref
- end
-
- ##
- # Cancel _all_ notification registrations. Simple and clean, but a
- # blunt tool at best. This will have to do for the time being...
- #
- # @return [nil]
- def unregister_all
- @notifs.keys.each do |notif|
- unregister notif
- end
- end
-
-
- private
-
- def create_callback_for proc
- # we are ignoring the context pointer since this is OO
- Proc.new do |observer, sender, received_notif, _|
- break unless proc.call(received_notif, sender)
- unregister received_notif
- CFRunLoopStop(run_loop)
- end
- end
-
-end
View
@@ -315,31 +315,68 @@ def method_missing method, *args
# @group Notifications
+ def notifs
+ @notifs ||= {}
+ end
+
##
- # Register a callback block to run when a notification is sent by
- # the object.
+ # Register to receive notification of the given event being completed
+ # by the given element.
+ #
+ # {file:docs/Notifications.markdown Notifications} are a way to put
+ # non-polling delays into your scripts.
+ #
+ # Use this method to register to be notified of the specified event in
+ # an application.
#
# The block is optional. The block will be given the sender of the
# notification, which will almost always be `self`, and also the name
# of the notification being received. The block should return a
# boolean value that decides if the notification received is the
# expected one.
#
- # Read the {file:docs/Notifications.markdown Notifications tutorial}
- # for more information.
+ # @example
#
- # @param [#to_s]
- # @yieldparam [String]
- # @yieldparam [AX::Element]
+ # on_notification(:window_created) { |sender|
+ # puts "#{sender.inspect} sent the ':window_created' notification"
+ # true
+ # }
+ #
+ # @param [#to_s] notif the name of the notification
+ # @yield Validate the notification; the block should return truthy if
+ # the notification received is the expected one and the script can
+ # stop waiting, otherwise should return falsy.
+ # @yieldparam [String] notif the name of the notification
+ # @yieldparam [AXUIElementRef] element the element that sent the notification
# @yieldreturn [Boolean]
- # @return [Array(String,self)] the notification/element pair
+ # @return [Array(Observer, String, CFRunLoopSource)]
def on_notification name, &block
- notif = TRANSLATOR.guess_notification_for name
- register_to_receive notif, from: @ref do |notification, sender|
- element = process sender
- block ? block.call(notification, element) : true
+ notif = TRANSLATOR.guess_notification_for name
+ observer = observer_for self.pid, &notif_callback_for(&block)
+ source = run_loop_source_for observer
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), source, KCFRunLoopDefaultMode)
+ register observer, to_receive: notif, from: @ref
+ notifs[name] = [observer, notif, source]
+ end
+
+ def unregister_notification name
+ unless notifs.has_key? name
+ raise ArgumentError, "You have no registrations for #{name}"
end
- [notif, self]
+ _unregister_notification *notifs.delete(name)[0..1]
+ end
+
+ ##
+ # Cancel _all_ notification registrations for this object. Simple and
+ # clean, but a blunt tool at best. This will have to do for the time
+ # being...
+ #
+ # @return [nil]
+ def unregister_all
+ notifs.keys.each do |notif|
+ unregister_notification notif
+ end
+ nil
end
# @endgroup
@@ -439,4 +476,23 @@ def lookup key, with: values
return value if values.include? value
end
+ def notif_callback_for &block
+ # we are ignoring the context pointer since this is OO
+ Proc.new do |observer, sender, notif, _|
+ break unless block.call(process sender) if block
+ _unregister_notification observer, notif
+ CFRunLoopStop(CFRunLoopGetCurrent())
+ end
+ end
+
+ ##
+ # @todo What are the implications of not removing the run loop source?
+ # Taking it out would clobber other notifications that are using
+ # the same source, so we would have to check if we can remove it.
+ #
+ def _unregister_notification observer, notif
+ # @todo remove run loop source?
+ unregister observer, from_receiving: notif, from: @ref
+ end
+
end

0 comments on commit fe98f43

Please sign in to comment.