dag-amazing 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +202 -0
- data/README.rdoc +72 -0
- data/bin/amazing +19 -0
- data/lib/amazing.rb +24 -0
- data/lib/amazing/awesome.rb +46 -0
- data/lib/amazing/cli.rb +66 -0
- data/lib/amazing/cli/commands.rb +240 -0
- data/lib/amazing/cli/helpers.rb +159 -0
- data/lib/amazing/cli/initializers.rb +60 -0
- data/lib/amazing/config.rb +66 -0
- data/lib/amazing/config/dsl.rb +32 -0
- data/lib/amazing/config/dsl/awesome.rb +26 -0
- data/lib/amazing/config/dsl/awesome/widget.rb +27 -0
- data/lib/amazing/config/yaml.rb +11 -0
- data/lib/amazing/helpers/pango_markup.rb +26 -0
- data/lib/amazing/numeric.rb +50 -0
- data/lib/amazing/options.rb +93 -0
- data/lib/amazing/proc_file.rb +59 -0
- data/lib/amazing/string.rb +19 -0
- data/lib/amazing/widget.rb +140 -0
- data/lib/amazing/widgets.rb +37 -0
- data/lib/amazing/widgets/ac_adapter.rb +31 -0
- data/lib/amazing/widgets/alsa.rb +35 -0
- data/lib/amazing/widgets/battery.rb +51 -0
- data/lib/amazing/widgets/clock.rb +31 -0
- data/lib/amazing/widgets/cpu_info.rb +35 -0
- data/lib/amazing/widgets/cpu_usage.rb +50 -0
- data/lib/amazing/widgets/file.rb +44 -0
- data/lib/amazing/widgets/file_system.rb +42 -0
- data/lib/amazing/widgets/gmail.rb +61 -0
- data/lib/amazing/widgets/maildir.rb +34 -0
- data/lib/amazing/widgets/memory.rb +47 -0
- data/lib/amazing/widgets/moc.rb +80 -0
- data/lib/amazing/widgets/mpd.rb +146 -0
- data/lib/amazing/widgets/net_traffic.rb +50 -0
- data/lib/amazing/widgets/noop.rb +24 -0
- data/lib/amazing/widgets/pacman.rb +34 -0
- data/lib/amazing/widgets/raggle.rb +42 -0
- data/lib/amazing/widgets/sup.rb +38 -0
- data/lib/amazing/x11.rb +15 -0
- data/lib/amazing/x11/display_name.rb +50 -0
- metadata +101 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Amazing
|
16
|
+
class CLI
|
17
|
+
module Helpers
|
18
|
+
private
|
19
|
+
|
20
|
+
def parse_options
|
21
|
+
@options.parse
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_loglevel
|
25
|
+
begin
|
26
|
+
@log.level = Logger.const_get(@options[:loglevel].upcase)
|
27
|
+
|
28
|
+
rescue NameError
|
29
|
+
@log.error("Unsupported log level #{@options[:loglevel].inspect}")
|
30
|
+
@log.level = Logger::INFO
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop_process(log=true)
|
35
|
+
Process.kill("SIGINT", File.read("#{ENV["HOME"]}/.amazing/pids/#{@display.display}.pid").to_i)
|
36
|
+
@log.warn("Killed older process") if log
|
37
|
+
rescue
|
38
|
+
end
|
39
|
+
|
40
|
+
def load_scripts
|
41
|
+
scripts = @options[:include]
|
42
|
+
|
43
|
+
if @options[:autoinclude]
|
44
|
+
scripts << Dir["#{ENV["HOME"]}/.amazing/widgets/*"]
|
45
|
+
end
|
46
|
+
|
47
|
+
scripts.flatten.each do |script|
|
48
|
+
if File.exist?(script)
|
49
|
+
@log.debug("Loading script #{script.inspect}")
|
50
|
+
|
51
|
+
begin
|
52
|
+
Widgets.module_eval(File.read(script), script)
|
53
|
+
|
54
|
+
rescue SyntaxError => e
|
55
|
+
@log.error("Bad syntax in #{script} at line #{e.to_s.scan(/:(\d+)/)}")
|
56
|
+
end
|
57
|
+
|
58
|
+
else
|
59
|
+
@log.error("No such widget script #{script.inspect}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_config
|
65
|
+
@log.debug("Parsing configuration file")
|
66
|
+
|
67
|
+
begin
|
68
|
+
@config = Config.new(@options[:config])
|
69
|
+
|
70
|
+
rescue
|
71
|
+
@log.fatal("Unable to parse configuration file, exiting")
|
72
|
+
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def wait_for_sockets
|
78
|
+
@log.debug("Waiting for awesome control socket for display #{@display.display}")
|
79
|
+
|
80
|
+
begin
|
81
|
+
Timeout.timeout(30) do
|
82
|
+
sleep 1 until File.exist?("#{ENV["HOME"]}/.awesome_ctl.#{@display.display}")
|
83
|
+
@log.debug("Got socket for display #{@display.display}")
|
84
|
+
end
|
85
|
+
|
86
|
+
rescue Timeout::Error
|
87
|
+
@log.fatal("Socket for display #{@display.display} not created within 30 seconds, exiting")
|
88
|
+
|
89
|
+
exit 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def save_pid
|
94
|
+
path = "#{ENV["HOME"]}/.amazing/pids"
|
95
|
+
FileUtils.makedirs(path)
|
96
|
+
|
97
|
+
File.open("#{path}/#{@display.display}.pid", "w+") do |f|
|
98
|
+
f.write($$)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def remove_pid
|
103
|
+
File.delete("#{ENV["HOME"]}/.amazing/pids/#{@display.display}.pid") rescue Errno::ENOENT
|
104
|
+
end
|
105
|
+
|
106
|
+
def set_traps
|
107
|
+
trap("SIGINT") do
|
108
|
+
@log.fatal("Received SIGINT, exiting")
|
109
|
+
remove_pid
|
110
|
+
exit
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def update_non_interval
|
115
|
+
@threads << Thread.new do
|
116
|
+
@config[:awesome].each do |awesome|
|
117
|
+
awesome[:widgets].each do |widget|
|
118
|
+
next if widget[:interval]
|
119
|
+
|
120
|
+
@threads << Thread.new(awesome, widget) do |awesome, widget|
|
121
|
+
update_widget(awesome[:screen], awesome[:statusbar], widget)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def update_widget(screen, statusbar, widget, iteration=0)
|
129
|
+
threads = []
|
130
|
+
@log.debug("Updating widget #{widget[:identifier]} of type #{widget[:module]} on screen #{screen}")
|
131
|
+
|
132
|
+
begin
|
133
|
+
mod = Widgets.const_get(widget[:module]).new(widget.merge(:iteration => iteration))
|
134
|
+
|
135
|
+
if widget[:properties].empty?
|
136
|
+
threads << Thread.new(screen, statusbar, widget, mod) do |screen, statusbar, widget, mod|
|
137
|
+
@awesome.widget_tell(screen, statusbar, widget[:identifier], widget[:property], mod.formatize)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
widget[:properties].each do |property, format|
|
142
|
+
threads << Thread.new(screen, statusbar, widget, property, mod, format) do |screen, statusbar, widget, property, mod, format|
|
143
|
+
@awesome.widget_tell(screen, statusbar, widget[:identifier], property, mod.formatize(format))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
rescue WidgetError => e
|
148
|
+
@log.error(widget[:module]) { e.message }
|
149
|
+
end
|
150
|
+
|
151
|
+
threads.each {|t| t.join }
|
152
|
+
end
|
153
|
+
|
154
|
+
def join_threads
|
155
|
+
@threads.each {|t| t.join }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Amazing
|
16
|
+
class CLI
|
17
|
+
module Initializers
|
18
|
+
private
|
19
|
+
|
20
|
+
def initialize_threads
|
21
|
+
@threads = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize_encoding
|
25
|
+
$KCODE = "utf-8"
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize_logger
|
29
|
+
@log = Logger.new(STDOUT)
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize_options
|
33
|
+
@options = Options.new(@args)
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize_display
|
37
|
+
begin
|
38
|
+
@display = X11::DisplayName.new
|
39
|
+
|
40
|
+
rescue X11::EmptyDisplayName => e
|
41
|
+
@log.warn("#{e.message}, falling back on :0")
|
42
|
+
@display = X11::DisplayName.new(":0")
|
43
|
+
|
44
|
+
rescue X11::InvalidDisplayName => e
|
45
|
+
@log.fatal("#{e.message}, exiting")
|
46
|
+
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize_awesome
|
52
|
+
@awesome = Awesome.new(@display.display)
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize_exit
|
56
|
+
at_exit { Thread.list.each {|t| t.exit } }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'amazing/string'
|
2
|
+
require 'amazing/config/dsl'
|
3
|
+
require 'amazing/config/yaml'
|
4
|
+
|
5
|
+
module Amazing
|
6
|
+
class Config < Hash
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
case File.extname(@config)[1..-1].to_sym
|
10
|
+
when :rb
|
11
|
+
from_dsl
|
12
|
+
when :yml, :yaml
|
13
|
+
from_yaml
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def from_dsl
|
20
|
+
dsl = Dsl.new(@config)
|
21
|
+
self[:awesome] = []
|
22
|
+
dsl.awesome_statusbars.each do |awesome|
|
23
|
+
self[:awesome] << {}
|
24
|
+
self[:awesome][-1][:screen] = awesome.options[:screen] || 0
|
25
|
+
self[:awesome][-1][:statusbar] = awesome.options[:statusbar] || "mystatusbar"
|
26
|
+
self[:awesome][-1][:widgets] = []
|
27
|
+
awesome.widgets.each do |widget|
|
28
|
+
self[:awesome][-1][:widgets] << {}
|
29
|
+
self[:awesome][-1][:widgets][-1][:identifier] = widget.identifier
|
30
|
+
self[:awesome][-1][:widgets][-1][:properties] = widget.properties
|
31
|
+
self[:awesome][-1][:widgets][-1].merge!(widget.options)
|
32
|
+
self[:awesome][-1][:widgets][-1][:module] ||= widget.identifier
|
33
|
+
self[:awesome][-1][:widgets][-1][:property] ||= "text"
|
34
|
+
self[:awesome][-1][:widgets][-1][:module] = self[:awesome][-1][:widgets][-1][:module].to_s.camel_case
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def from_yaml
|
40
|
+
yaml = Yaml.new(@config)
|
41
|
+
self[:awesome] = []
|
42
|
+
yaml["awesome"].each do |awesome|
|
43
|
+
self[:awesome] << {}
|
44
|
+
self[:awesome][-1][:screen] = awesome["screen"] || 0
|
45
|
+
self[:awesome][-1][:statusbar] = awesome["statusbar"] || "mystatusbar"
|
46
|
+
self[:awesome][-1][:widgets] = []
|
47
|
+
awesome["widgets"].each do |widget|
|
48
|
+
self[:awesome][-1][:widgets] << {}
|
49
|
+
case widget
|
50
|
+
when Hash
|
51
|
+
self[:awesome][-1][:widgets][-1][:identifier] = widget.keys[0]
|
52
|
+
widget.values[0].each do |key, value|
|
53
|
+
self[:awesome][-1][:widgets][-1][key.to_sym] = value
|
54
|
+
end
|
55
|
+
self[:awesome][-1][:widgets][-1][:module] ||= widget.keys[0]
|
56
|
+
when String
|
57
|
+
self[:awesome][-1][:widgets][-1][:identifier] = widget
|
58
|
+
self[:awesome][-1][:widgets][-1][:module] = widget
|
59
|
+
end
|
60
|
+
self[:awesome][-1][:widgets][-1][:property] ||= "text"
|
61
|
+
self[:awesome][-1][:widgets][-1][:module] = self[:awesome][-1][:widgets][-1][:module].to_s.camel_case
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'amazing/config/dsl/awesome'
|
2
|
+
require 'amazing/numeric'
|
3
|
+
|
4
|
+
module Amazing
|
5
|
+
class Config < Hash
|
6
|
+
class Dsl
|
7
|
+
attr_reader :awesome_statusbars
|
8
|
+
|
9
|
+
def initialize(config=nil, &block)
|
10
|
+
@awesome_statusbars = []
|
11
|
+
if config
|
12
|
+
config = File.expand_path(config)
|
13
|
+
@relative_path = File.dirname(config)
|
14
|
+
import(config)
|
15
|
+
end
|
16
|
+
import(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def import(config=nil, &block)
|
20
|
+
if config
|
21
|
+
config = "#@relative_path/#{config}" if config[0] != ?/
|
22
|
+
instance_eval(File.read(config))
|
23
|
+
end
|
24
|
+
instance_eval(&block) if block
|
25
|
+
end
|
26
|
+
|
27
|
+
def awesome(opts={}, &block)
|
28
|
+
@awesome_statusbars << Awesome.new(opts, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'amazing/config/dsl/awesome/widget'
|
2
|
+
|
3
|
+
module Amazing
|
4
|
+
class Config < Hash
|
5
|
+
class Dsl
|
6
|
+
class Awesome
|
7
|
+
attr_reader :options
|
8
|
+
attr_reader :widgets
|
9
|
+
|
10
|
+
def initialize(opts={}, &block)
|
11
|
+
@options = opts
|
12
|
+
@widgets = []
|
13
|
+
instance_eval(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(opts)
|
17
|
+
@options.merge!(opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
def widget(identifier, opts={}, &block)
|
21
|
+
@widgets << Widget.new(identifier, opts, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Amazing
|
2
|
+
class Config < Hash
|
3
|
+
class Dsl
|
4
|
+
class Awesome
|
5
|
+
class Widget
|
6
|
+
attr_reader :options
|
7
|
+
attr_reader :identifier
|
8
|
+
attr_reader :properties
|
9
|
+
|
10
|
+
def initialize(identifier, opts={}, &block)
|
11
|
+
@identifier, @options = identifier, opts
|
12
|
+
@properties = {}
|
13
|
+
instance_eval(&block) if block
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(opts)
|
17
|
+
@options.merge!(opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
def property(name, &block)
|
21
|
+
@properties[name] = block
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Amazing
|
2
|
+
module Helpers
|
3
|
+
module PangoMarkup
|
4
|
+
def span(text, opts)
|
5
|
+
attrs = opts.map {|key, value| "#{key}=#{value.to_s.inspect}" }.join(" ")
|
6
|
+
"<span #{attrs}>#{text}</span>"
|
7
|
+
end
|
8
|
+
|
9
|
+
def background(color, text)
|
10
|
+
span(text, :background => color)
|
11
|
+
end
|
12
|
+
|
13
|
+
def foreground(color, text)
|
14
|
+
span(text, :foreground => color)
|
15
|
+
end
|
16
|
+
|
17
|
+
def underline(text, style=:single)
|
18
|
+
span(text, :underline => style)
|
19
|
+
end
|
20
|
+
|
21
|
+
def bold(text, level=:bold)
|
22
|
+
span(text, :weight => level)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
class Numeric
|
16
|
+
def seconds
|
17
|
+
self
|
18
|
+
end
|
19
|
+
alias :second :seconds
|
20
|
+
|
21
|
+
def minutes
|
22
|
+
self * 60
|
23
|
+
end
|
24
|
+
alias :minute :minutes
|
25
|
+
|
26
|
+
def hours
|
27
|
+
minutes * 60
|
28
|
+
end
|
29
|
+
alias :hour :hours
|
30
|
+
|
31
|
+
def days
|
32
|
+
hours * 24
|
33
|
+
end
|
34
|
+
alias :day :days
|
35
|
+
|
36
|
+
def weeks
|
37
|
+
days * 7
|
38
|
+
end
|
39
|
+
alias :week :weeks
|
40
|
+
|
41
|
+
def months
|
42
|
+
weeks * 4
|
43
|
+
end
|
44
|
+
alias :month :months
|
45
|
+
|
46
|
+
def years
|
47
|
+
months * 12
|
48
|
+
end
|
49
|
+
alias :year :years
|
50
|
+
end
|