appfactory 0.1
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.
- data/.DS_Store +0 -0
- data/History.txt +6 -0
- data/Manifest.txt +18 -0
- data/README.txt +48 -0
- data/Rakefile +16 -0
- data/bin/appfactory +109 -0
- data/examples/appmain.rb +26 -0
- data/lib/appfactory.rb +3 -0
- data/template/appfactory.app.template/Contents/Info.plist +26 -0
- data/template/appfactory.app.template/Contents/MacOS/appfactory +0 -0
- data/template/appfactory.app.template/Contents/PkgInfo +1 -0
- data/template/appfactory.app.template/Contents/Resources/English.lproj/InfoPlist.strings +0 -0
- data/template/appfactory.app.template/Contents/Resources/English.lproj/MainMenu.nib/designable.nib +2398 -0
- data/template/appfactory.app.template/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib +0 -0
- data/template/appfactory.app.template/Contents/Resources/growl.rb +168 -0
- data/template/appfactory.app.template/Contents/Resources/rb_main.rb +171 -0
- data/template/appfactory.app.template/Contents/Resources/ruby.icns +0 -0
- data/template/appfactory.app.template/Contents/Resources/ruby_statusbar.png +0 -0
- metadata +105 -0
data/template/appfactory.app.template/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
ADDED
Binary file
|
@@ -0,0 +1,168 @@
|
|
1
|
+
#
|
2
|
+
# Code stolen from HotCocoa examples: http://macruby.org
|
3
|
+
#
|
4
|
+
module Growl
|
5
|
+
class Notifier
|
6
|
+
VERSION = '1.0.1'
|
7
|
+
|
8
|
+
GROWL_IS_READY = "Lend Me Some Sugar; I Am Your Neighbor!"
|
9
|
+
GROWL_NOTIFICATION_CLICKED = "GrowlClicked!"
|
10
|
+
GROWL_NOTIFICATION_TIMED_OUT = "GrowlTimedOut!"
|
11
|
+
GROWL_KEY_CLICKED_CONTEXT = "ClickedContext"
|
12
|
+
|
13
|
+
PRIORITIES = {
|
14
|
+
:emergency => 2,
|
15
|
+
:high => 1,
|
16
|
+
:normal => 0,
|
17
|
+
:moderate => -1,
|
18
|
+
:very_low => -2,
|
19
|
+
}
|
20
|
+
|
21
|
+
class << self
|
22
|
+
# Returns the singleton instance of Growl::Notifier with which you register and send your Growl notifications.
|
23
|
+
def sharedInstance
|
24
|
+
@sharedInstance ||= alloc.init
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :application_name, :application_icon, :notifications, :default_notifications
|
29
|
+
attr_accessor :delegate
|
30
|
+
|
31
|
+
# Registers the applications metadata and the notifications, that your application might send, to Growl.
|
32
|
+
# The +default_notifications+ are notifications that will be enabled by default, the regular +notifications+ are
|
33
|
+
# optional and should be enabled by the user in the Growl system preferences.
|
34
|
+
#
|
35
|
+
# Register the applications name and the notifications that will be used.
|
36
|
+
# * +default_notifications+ defaults to the regular +notifications+.
|
37
|
+
# * +application_icon+ defaults to NSApplication.sharedApplication.applicationIconImage.
|
38
|
+
#
|
39
|
+
# Growl::Notifier.sharedInstance.register 'FoodApp', ['YourHamburgerIsReady', 'OhSomeoneElseAteIt']
|
40
|
+
#
|
41
|
+
# Register the applications name, the notifications plus the default notifications that will be used and the icon that's to be used in the Growl notifications.
|
42
|
+
#
|
43
|
+
# Growl::Notifier.sharedInstance.register 'FoodApp', ['YourHamburgerIsReady', 'OhSomeoneElseAteIt'], ['DefaultNotification], NSImage.imageNamed('GreasyHamburger')
|
44
|
+
def register(application_name, notifications, default_notifications = nil, application_icon = nil)
|
45
|
+
@application_name, @application_icon = application_name, (application_icon || NSApplication.sharedApplication.applicationIconImage)
|
46
|
+
@notifications, @default_notifications = notifications, (default_notifications || notifications)
|
47
|
+
@callbacks = {}
|
48
|
+
send_registration!
|
49
|
+
end
|
50
|
+
|
51
|
+
# Sends a Growl notification.
|
52
|
+
#
|
53
|
+
# * +notification_name+ : the name of one of the notifcations that your apllication registered with Growl. See register for more info.
|
54
|
+
# * +title+ : the title that should be used in the Growl notification.
|
55
|
+
# * +description+ : the body of the Grow notification.
|
56
|
+
# * +options+ : specifies a few optional options:
|
57
|
+
# * <tt>:sticky</tt> : indicates if the Grow notification should "stick" to the screen. Defaults to +false+.
|
58
|
+
# * <tt>:priority</tt> : sets the priority level of the Growl notification. Defaults to 0.
|
59
|
+
# * <tt>:icon</tt> : specifies the icon to be used in the Growl notification. Defaults to the registered +application_icon+, see register for more info.
|
60
|
+
#
|
61
|
+
# Simple example:
|
62
|
+
#
|
63
|
+
# name = 'YourHamburgerIsReady'
|
64
|
+
# title = 'Your hamburger is ready for consumption!'
|
65
|
+
# description = 'Please pick it up at isle 4.'
|
66
|
+
#
|
67
|
+
# Growl::Notifier.sharedInstance.notify(name, title, description)
|
68
|
+
#
|
69
|
+
# Example with optional options:
|
70
|
+
#
|
71
|
+
# Growl::Notifier.sharedInstance.notify(name, title, description, :sticky => true, :priority => 1, :icon => NSImage.imageNamed('SuperBigHamburger'))
|
72
|
+
#
|
73
|
+
# When you pass notify a block, that block will be used as the callback handler if the Growl notification was clicked. Eg:
|
74
|
+
#
|
75
|
+
# Growl::Notifier.sharedInstance.notify(name, title, description, :sticky => true) do
|
76
|
+
# user_clicked_notification_so_do_something!
|
77
|
+
# end
|
78
|
+
def notify(notification_name, title, description, options = {}, &callback)
|
79
|
+
dict = {
|
80
|
+
:ApplicationName => @application_name,
|
81
|
+
:ApplicationPID => pid,
|
82
|
+
:NotificationName => notification_name,
|
83
|
+
:NotificationTitle => title,
|
84
|
+
:NotificationDescription => description,
|
85
|
+
:NotificationPriority => PRIORITIES[options[:priority]] || options[:priority] || 0
|
86
|
+
}
|
87
|
+
dict[:NotificationIcon] = options[:icon].TIFFRepresentation if options[:icon]
|
88
|
+
dict[:NotificationSticky] = 1 if options[:sticky]
|
89
|
+
|
90
|
+
context = {}
|
91
|
+
context[:user_click_context] = options[:click_context] if options[:click_context]
|
92
|
+
if block_given?
|
93
|
+
@callbacks[callback.object_id] = callback
|
94
|
+
context[:callback_object_id] = callback.object_id.to_s
|
95
|
+
end
|
96
|
+
dict[:NotificationClickContext] = context unless context.empty?
|
97
|
+
|
98
|
+
notification_center.postNotificationName :GrowlNotification, object:nil, userInfo:dict, deliverImmediately:true
|
99
|
+
end
|
100
|
+
|
101
|
+
def onReady(notification)
|
102
|
+
send_registration!
|
103
|
+
end
|
104
|
+
|
105
|
+
def onClicked(notification)
|
106
|
+
user_context = nil
|
107
|
+
if context = notification.userInfo[GROWL_KEY_CLICKED_CONTEXT]
|
108
|
+
user_context = context[:user_click_context]
|
109
|
+
if callback_object_id = context[:callback_object_id]
|
110
|
+
@callbacks.delete(callback_object_id.to_i).call
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
@delegate.growlNotifierClicked_context(self, user_context) if @delegate && @delegate.respond_to?(:growlNotifierClicked_context)
|
115
|
+
end
|
116
|
+
|
117
|
+
def onTimeout(notification)
|
118
|
+
user_context = nil
|
119
|
+
if context = notification.userInfo[GROWL_KEY_CLICKED_CONTEXT]
|
120
|
+
@callbacks.delete(context[:callback_object_id].to_i) if context[:callback_object_id]
|
121
|
+
user_context = context[:user_click_context]
|
122
|
+
end
|
123
|
+
|
124
|
+
@delegate.growlNotifierTimedOut_context(self, user_context) if @delegate && @delegate.respond_to?(:growlNotifierTimedOut_context)
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def pid
|
130
|
+
NSProcessInfo.processInfo.processIdentifier.to_i
|
131
|
+
end
|
132
|
+
|
133
|
+
def notification_center
|
134
|
+
NSDistributedNotificationCenter.defaultCenter
|
135
|
+
end
|
136
|
+
|
137
|
+
def send_registration!
|
138
|
+
add_observer 'onReady:', GROWL_IS_READY, false
|
139
|
+
add_observer 'onClicked:', GROWL_NOTIFICATION_CLICKED, true
|
140
|
+
add_observer 'onTimeout:', GROWL_NOTIFICATION_TIMED_OUT, true
|
141
|
+
|
142
|
+
dict = {
|
143
|
+
:ApplicationName => @application_name,
|
144
|
+
:ApplicationIcon => application_icon.TIFFRepresentation,
|
145
|
+
:AllNotifications => @notifications,
|
146
|
+
:DefaultNotifications => @default_notifications
|
147
|
+
}
|
148
|
+
|
149
|
+
notification_center.postNotificationName :GrowlApplicationRegistrationNotification, object:nil, userInfo:dict, deliverImmediately:true
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_observer(selector, name, prepend_name_and_pid)
|
153
|
+
name = "#{@application_name}-#{pid}-#{name}" if prepend_name_and_pid
|
154
|
+
notification_center.addObserver self, selector:selector, name:name, object:nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.growl(name, title, description, options = {}, &callback)
|
159
|
+
Growl::Notifier.sharedInstance.notify name, title, description, options, &callback
|
160
|
+
end
|
161
|
+
|
162
|
+
# Sends a sticky Growl notification. See Growl::Notifier#notify for more info.
|
163
|
+
def self.sticky_growl(name, title, description, options = {}, &callback)
|
164
|
+
growl name, title, description, options.merge!(:sticky => true), &callback
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
framework 'Cocoa'
|
2
|
+
$: << NSBundle.mainBundle.resourcePath.fileSystemRepresentation
|
3
|
+
require 'growl'
|
4
|
+
|
5
|
+
module AppFactory
|
6
|
+
def self.resources_dir
|
7
|
+
NSBundle.mainBundle.resourcePath.fileSystemRepresentation
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.app_name
|
11
|
+
@app_name || 'AppFactory'
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.app_name=(name)
|
15
|
+
@app_name = name
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.debug(msg)
|
19
|
+
NSLog "DEBUG [#{app_name}]: #{msg}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def register_growl_events(array = [])
|
23
|
+
a = array.map { |e| e.to_s }
|
24
|
+
Growl::Notifier.sharedInstance.register AppFactory.app_name, array
|
25
|
+
end
|
26
|
+
|
27
|
+
def growl(event_name, title, desc)
|
28
|
+
Growl.growl event_name.to_s, title, desc
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.top_menu
|
32
|
+
if not @top_menu
|
33
|
+
@top_menu = NSMenu.new
|
34
|
+
@top_menu.initWithTitle app_name
|
35
|
+
@top_menu
|
36
|
+
else
|
37
|
+
debug 'Meny already initialized...'
|
38
|
+
@top_menu
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def clear_menu(menu)
|
43
|
+
menu.itemArray.each do |mi|
|
44
|
+
menu.removeItem mi
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.terminate
|
49
|
+
@app.terminate(self)
|
50
|
+
end
|
51
|
+
|
52
|
+
def open_url(url)
|
53
|
+
NSWorkspace.sharedWorkspace.openURL(NSURL.URLWithString(url))
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.status_bar
|
57
|
+
if not @status_bar
|
58
|
+
@status_bar = NSStatusBar.systemStatusBar
|
59
|
+
@status_item = @status_bar.statusItemWithLength(NSVariableStatusItemLength)
|
60
|
+
@status_item.setMenu top_menu
|
61
|
+
img = NSImage.new.initWithContentsOfFile "#{AppFactory.resources_dir}/ruby_statusbar.png"
|
62
|
+
@status_item.setImage(img)
|
63
|
+
Growl.growl 'InitDone', app_name, "Here we go!"
|
64
|
+
@status_bar
|
65
|
+
else
|
66
|
+
debug 'Statusbar already initialized...'
|
67
|
+
@status_bar
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.start
|
72
|
+
@app = NSApplication.sharedApplication
|
73
|
+
status_bar
|
74
|
+
@app.run
|
75
|
+
end
|
76
|
+
|
77
|
+
def timer(interval, &block)
|
78
|
+
delegate = TimerDelegate.new
|
79
|
+
@timer = NSTimer.scheduledTimerWithTimeInterval interval.to_f, :target => delegate, :selector => "runTimer:", :userInfo => nil, :repeats => true
|
80
|
+
TimerDelegate.send(:class_eval, "def timerBlock=(blk); @timerBlock = blk; end")
|
81
|
+
delegate.send("timerBlock=".to_sym, block)
|
82
|
+
end
|
83
|
+
|
84
|
+
def menu_item(title, &block)
|
85
|
+
mi = NSMenuItem.new
|
86
|
+
mi.title = title
|
87
|
+
dname = "delegate#{rand(999999999)}"
|
88
|
+
mi.action = "#{dname}:"
|
89
|
+
AppFactoryDelegate.send(:class_eval, "def #{dname}=(blk); @#{dname} = blk; end")
|
90
|
+
AppFactoryDelegate.send(:class_eval, "def #{dname}(sender); @#{dname}.call ; end")
|
91
|
+
delegate = AppFactory.delegate
|
92
|
+
delegate.send("#{dname}=".to_sym, block)
|
93
|
+
mi.target = delegate
|
94
|
+
if @current_menu
|
95
|
+
@current_menu.addItem mi
|
96
|
+
else
|
97
|
+
AppFactory.menu.addItem mi
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def menu_separator
|
102
|
+
if @current_menu
|
103
|
+
@current_menu.addItem NSMenuItem.separatorItem
|
104
|
+
else
|
105
|
+
puts NSMenuItem.separatorItem
|
106
|
+
AppFactory.top_menu.addItem NSMenuItem.separatorItem
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def menu_quit
|
111
|
+
mi = NSMenuItem.new
|
112
|
+
mi.title = 'Quit'
|
113
|
+
mi.action = 'terminate:'
|
114
|
+
mi.target = AppFactory.delegate
|
115
|
+
AppFactory.top_menu.addItem mi
|
116
|
+
end
|
117
|
+
|
118
|
+
def menu(title)
|
119
|
+
if not @submenues
|
120
|
+
AppFactory.debug 'Init submenues collection'
|
121
|
+
@submenues = {}
|
122
|
+
end
|
123
|
+
m = nil
|
124
|
+
if @submenues.has_key? title
|
125
|
+
#existing menu
|
126
|
+
AppFactory.debug "Submenu #{title} already exists"
|
127
|
+
m = @submenues[title]
|
128
|
+
else
|
129
|
+
AppFactory.debug "Creating submenu #{title}"
|
130
|
+
m = NSMenu.new
|
131
|
+
@submenues[title] = m
|
132
|
+
m.initWithTitle title
|
133
|
+
mi = NSMenuItem.new
|
134
|
+
mi.title = title
|
135
|
+
mi.setSubmenu m
|
136
|
+
AppFactory.top_menu.addItem mi
|
137
|
+
end
|
138
|
+
@current_menu = m
|
139
|
+
yield m
|
140
|
+
@current_menu = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.delegate
|
144
|
+
@delegate ||= AppFactoryDelegate.new
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.vendor_libs
|
148
|
+
Dir["#{resources_dir}/vendor/gems/gems/*"].each do |d|
|
149
|
+
AppFactory.debug "Adding #{d}/lib to RUBYLIB"
|
150
|
+
$: << "#{d}/lib"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class TimerDelegate
|
155
|
+
def runTimer(timer)
|
156
|
+
@timerBlock.call
|
157
|
+
end
|
158
|
+
end
|
159
|
+
class AppFactoryDelegate
|
160
|
+
def terminate(sender)
|
161
|
+
AppFactory.terminate
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
AppFactory.vendor_libs
|
168
|
+
include AppFactory
|
169
|
+
require 'dsl'
|
170
|
+
|
171
|
+
AppFactory.start
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: appfactory
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sergio Rubio
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-02 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: choice
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.1.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: bundler
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0.7"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: hoe
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.3.3
|
44
|
+
version:
|
45
|
+
description: Easily create Status Bar Applications for Mac OS X
|
46
|
+
email:
|
47
|
+
- sergio@rubio.name
|
48
|
+
executables:
|
49
|
+
- appfactory
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
extra_rdoc_files:
|
53
|
+
- History.txt
|
54
|
+
- Manifest.txt
|
55
|
+
- README.txt
|
56
|
+
files:
|
57
|
+
- .DS_Store
|
58
|
+
- History.txt
|
59
|
+
- Manifest.txt
|
60
|
+
- README.txt
|
61
|
+
- Rakefile
|
62
|
+
- bin/appfactory
|
63
|
+
- examples/appmain.rb
|
64
|
+
- lib/appfactory.rb
|
65
|
+
- template/appfactory.app.template/Contents/Info.plist
|
66
|
+
- template/appfactory.app.template/Contents/MacOS/appfactory
|
67
|
+
- template/appfactory.app.template/Contents/PkgInfo
|
68
|
+
- template/appfactory.app.template/Contents/Resources/English.lproj/InfoPlist.strings
|
69
|
+
- template/appfactory.app.template/Contents/Resources/English.lproj/MainMenu.nib/designable.nib
|
70
|
+
- template/appfactory.app.template/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
|
71
|
+
- template/appfactory.app.template/Contents/Resources/growl.rb
|
72
|
+
- template/appfactory.app.template/Contents/Resources/rb_main.rb
|
73
|
+
- template/appfactory.app.template/Contents/Resources/ruby.icns
|
74
|
+
- template/appfactory.app.template/Contents/Resources/ruby_statusbar.png
|
75
|
+
has_rdoc: true
|
76
|
+
homepage: http://appfactory.netcorex.org
|
77
|
+
licenses: []
|
78
|
+
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options:
|
81
|
+
- --main
|
82
|
+
- README.txt
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: "0"
|
90
|
+
version:
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: "0"
|
96
|
+
version:
|
97
|
+
requirements: []
|
98
|
+
|
99
|
+
rubyforge_project: appfactory
|
100
|
+
rubygems_version: 1.3.5
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: Mac OS X StatusBar App Builder!
|
104
|
+
test_files: []
|
105
|
+
|