appfactory 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|