dag-amazing 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/LICENSE +202 -0
  2. data/README.rdoc +72 -0
  3. data/bin/amazing +19 -0
  4. data/lib/amazing.rb +24 -0
  5. data/lib/amazing/awesome.rb +46 -0
  6. data/lib/amazing/cli.rb +66 -0
  7. data/lib/amazing/cli/commands.rb +240 -0
  8. data/lib/amazing/cli/helpers.rb +159 -0
  9. data/lib/amazing/cli/initializers.rb +60 -0
  10. data/lib/amazing/config.rb +66 -0
  11. data/lib/amazing/config/dsl.rb +32 -0
  12. data/lib/amazing/config/dsl/awesome.rb +26 -0
  13. data/lib/amazing/config/dsl/awesome/widget.rb +27 -0
  14. data/lib/amazing/config/yaml.rb +11 -0
  15. data/lib/amazing/helpers/pango_markup.rb +26 -0
  16. data/lib/amazing/numeric.rb +50 -0
  17. data/lib/amazing/options.rb +93 -0
  18. data/lib/amazing/proc_file.rb +59 -0
  19. data/lib/amazing/string.rb +19 -0
  20. data/lib/amazing/widget.rb +140 -0
  21. data/lib/amazing/widgets.rb +37 -0
  22. data/lib/amazing/widgets/ac_adapter.rb +31 -0
  23. data/lib/amazing/widgets/alsa.rb +35 -0
  24. data/lib/amazing/widgets/battery.rb +51 -0
  25. data/lib/amazing/widgets/clock.rb +31 -0
  26. data/lib/amazing/widgets/cpu_info.rb +35 -0
  27. data/lib/amazing/widgets/cpu_usage.rb +50 -0
  28. data/lib/amazing/widgets/file.rb +44 -0
  29. data/lib/amazing/widgets/file_system.rb +42 -0
  30. data/lib/amazing/widgets/gmail.rb +61 -0
  31. data/lib/amazing/widgets/maildir.rb +34 -0
  32. data/lib/amazing/widgets/memory.rb +47 -0
  33. data/lib/amazing/widgets/moc.rb +80 -0
  34. data/lib/amazing/widgets/mpd.rb +146 -0
  35. data/lib/amazing/widgets/net_traffic.rb +50 -0
  36. data/lib/amazing/widgets/noop.rb +24 -0
  37. data/lib/amazing/widgets/pacman.rb +34 -0
  38. data/lib/amazing/widgets/raggle.rb +42 -0
  39. data/lib/amazing/widgets/sup.rb +38 -0
  40. data/lib/amazing/x11.rb +15 -0
  41. data/lib/amazing/x11/display_name.rb +50 -0
  42. 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,11 @@
1
+ require 'yaml'
2
+
3
+ module Amazing
4
+ class Config < Hash
5
+ class Yaml < Hash
6
+ def initialize(config)
7
+ merge!(YAML.load_file(config))
8
+ end
9
+ end
10
+ end
11
+ 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