dag-amazing 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.
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