Make the progress bars and graphs more configurable and themable
[delightful.git] / delightful / widgets / cpu.lua
1 -------------------------------------------------------------------------------
2 --
3 -- CPU widget for Awesome 3.5
4 -- Copyright (C) 2011-2016 Tuomas Jormola <tj@solitudo.net>
5 --
6 -- Licensed under the terms of GNU General Public License Version 2.0.
7 --
8 -- Description:
9 --
10 -- Displays horizontal usage trend graph of all the CPUs combined.
11 -- Also displays a CPU icon next to the graph. Clicking the icon
12 -- launches an external application (if configured).
13 --
14 -- Widget extends vicious.widgets.cpu from Vicious widget framework.
15 --
16 -- Widget tries to use an icon from the package mate-sensors-applet-common
17 -- if available.
18 --
19 --
20 -- Configuration:
21 --
22 -- The load() function can be supplied with configuration.
23 -- Format of the configuration is as follows.
24 -- {
25 -- -- Command to execute when left-clicking the widget icon.
26 -- -- Empty by default.
27 --        command         = 'gnome-system-monitor',
28 -- -- Don't try to display any icons. Default is false (i.e. display icons).
29 --        no_icon         = true,
30 -- -- Height of the graph in pixels. Default is 19.
31 --        graph_height    = 19,
32 -- -- Width of the graph in pixels. Default is 20.
33 --        graph_width     = 50,
34 -- -- How often update the widget data. Default is 1 second.
35 --        update_interval = 2
36 -- }
37 --
38 --
39 -- Theme:
40 --
41 -- The widget uses following settings, colors and icons if available in
42 -- the Awesome theme.
43 --
44 -- theme.graph_height     - height of the CPU graph in pixels
45 -- theme.graph_width      - width of the CPU graph in pixels
46 -- theme.bg_widget        - widget background color
47 -- theme.fg_widget        - widget foreground color
48 -- theme.fg_center_widget - widget gradient color, middle
49 -- theme.fg_end_widget    - widget gradient color, end
50 -- theme.delightful_cpu   - icon shown next to the CPU graph
51 ---
52 -------------------------------------------------------------------------------
53
54 local awful       = require('awful')
55 local wibox       = require('wibox')
56 local beautiful   = require('beautiful')
57
58 local delightful  = { utils = require('delightful.utils') }
59 local vicious     = require('vicious')
60
61 local pairs  = pairs
62 local string = { format = string.format }
63
64 module('delightful.widgets.cpu')
65
66 local cpu_config
67 local fatal_error
68 local icon_tooltip
69
70 local config_description = {
71         {
72                 name     = 'command',
73                 validate = function(value) return delightful.utils.config_string(value) end
74         },
75         {
76                 name     = 'no_icon',
77                 validate = function(value) return delightful.utils.config_boolean(value) end
78         },
79         {
80                 name     = 'graph_height',
81                 required = true,
82                 default  = 19,
83                 validate = function(value) return delightful.utils.config_int(value) end
84         },
85         {
86                 name     = 'graph_width',
87                 required = true,
88                 default  = 20,
89                 validate = function(value) return delightful.utils.config_int(value) end
90         },
91         {
92                 name     = 'update_interval',
93                 required = true,
94                 default  = 1,
95                 validate = function(value) return delightful.utils.config_int(value) end
96         },
97 }
98
99 local icon_description = {
100         cpu = { beautiful_name = 'delightful_cpu', default_icon = 'mate-sensors-applet-cpu' },
101 }
102
103 -- Configuration handler
104 function handle_config(user_config)
105         local empty_config = delightful.utils.get_empty_config(config_description)
106         if not user_config then
107                 user_config = empty_config
108         end
109         local config_data = delightful.utils.normalize_config(user_config, config_description)
110         local validation_errors = delightful.utils.validate_config(config_data, config_description)
111         if validation_errors then
112                 fatal_error = 'Configuration errors: \n'
113                 for error_index, error_entry in pairs(validation_errors) do
114                         fatal_error = string.format('%s %s', fatal_error, error_entry)
115                         if error_index < #validation_errors then
116                                 fatal_error = string.format('%s \n', fatal_error)
117                         end
118                 end
119                 cpu_config = empty_config
120                 return
121         end
122         cpu_config = config_data
123 end
124
125 -- Initalization
126 function load(self, config)
127         handle_config(config)
128         if fatal_error then
129                 delightful.utils.print_error('cpu', fatal_error)
130                 return nil, nil
131         end
132         local icon
133         local icon_files
134         if not cpu_config.no_icon then
135                 icon_files = delightful.utils.find_icon_files(icon_description)
136         end
137         local icon_file = icon_files and icon_files.cpu
138         if icon_file then
139                 local buttons = awful.button({}, 1, function()
140                         if not fatal_error and cpu_config.command then
141                                 awful.util.spawn(cpu_config.command, true)
142                         end
143                 end)
144                 icon = wibox.widget.imagebox()
145                 icon:buttons(buttons)
146                 icon:set_image(icon_file)
147                 icon_tooltip = awful.tooltip({ objects = { icon } })
148         end
149
150         local bg_color        = delightful.utils.find_theme_color({ 'bg_widget', 'bg_normal'                     })
151         local fg_color        = delightful.utils.find_theme_color({ 'fg_widget', 'fg_normal'                     })
152         local fg_center_color = delightful.utils.find_theme_color({ 'fg_center_widget', 'fg_widget', 'fg_normal' })
153         local fg_end_color    = delightful.utils.find_theme_color({ 'fg_end_widget', 'fg_widget', 'fg_normal'    })
154
155         local cpu_widget = awful.widget.graph()
156         if bg_color then
157                 cpu_widget:set_background_color(bg_color)
158                 cpu_widget:set_border_color(bg_color)
159         end
160         local color_args = fg_color
161         local height = beautiful.graph_height or cpu_config.graph_height
162         local width  = beautiful.graph_width  or cpu_config.graph_width
163         if fg_color and fg_center_color and fg_end_color then
164                 color_args = {
165                         type = 'linear',
166                         from = { width / 2, 0 },
167                         to = { width / 2, height },
168                         stops = {{ 0, fg_end_color }, { 0.5, fg_center_color }, { 1, fg_color }},
169                 }
170         end
171         cpu_widget:set_color(color_args)
172         cpu_widget:set_width(width)
173         cpu_widget:set_height(height)
174         local w = wibox.layout.fixed.horizontal()
175         w:add(cpu_widget)
176         vicious.register(cpu_widget, vicious.widgets.cpu, vicious_formatter, cpu_config.update_interval)
177
178         return { w }, { icon }
179 end
180
181 -- Vicious display formatter, also update widget tooltip
182 function vicious_formatter(widget, data)
183         if icon_tooltip then
184                 local tooltip_text = string.format(' CPU usage trend graph of all the CPUs in the system \n Current CPU usage: %d%% ', data[1])
185                 icon_tooltip:set_text(tooltip_text)
186         end
187         return data[1]
188 end