commit 7524b323935390881f85e6d8a5c76941ef7e321f Author: petrucci4prez Date: Thu Aug 11 23:25:56 2016 -0400 init diff --git a/.conkyrc b/.conkyrc new file mode 100644 index 0000000..28ce15d --- /dev/null +++ b/.conkyrc @@ -0,0 +1,36 @@ +conky.config = { + background = true, + + --adjust cpu dial sensitivity (1-14) + cpu_avg_samples = 4, + net_avg_samples = 14, + + out_to_console = false, + + own_window = true, + own_window_type = 'desktop', + own_window_transparent = true, + own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager', + + double_buffer = true, + minimum_width = 1377, + minimum_height = 778, + + draw_shades = false, + draw_outline = false, + draw_borders = false, + gap_x = 0, + gap_y = 0, + alignment = 'top_left', + + no_buffers = true, + + --Lua Load + lua_load = '/home/ndwar_9355/.local/share/conky/default/main.lua', + lua_draw_hook_pre = 'main' +} + +--control updates entirely in lua + +conky.text = [[]] + diff --git a/images/weather/am_pcloudy.png b/images/weather/am_pcloudy.png new file mode 100644 index 0000000..096fb6b Binary files /dev/null and b/images/weather/am_pcloudy.png differ diff --git a/images/weather/am_pcloudyr.png b/images/weather/am_pcloudyr.png new file mode 100644 index 0000000..ac8698d Binary files /dev/null and b/images/weather/am_pcloudyr.png differ diff --git a/images/weather/am_showers.png b/images/weather/am_showers.png new file mode 100644 index 0000000..8e34692 Binary files /dev/null and b/images/weather/am_showers.png differ diff --git a/images/weather/am_snowshowers.png b/images/weather/am_snowshowers.png new file mode 100644 index 0000000..85efb4f Binary files /dev/null and b/images/weather/am_snowshowers.png differ diff --git a/images/weather/am_tstorm.png b/images/weather/am_tstorm.png new file mode 100644 index 0000000..d64955f Binary files /dev/null and b/images/weather/am_tstorm.png differ diff --git a/images/weather/blizzard.png b/images/weather/blizzard.png new file mode 100644 index 0000000..18fa272 Binary files /dev/null and b/images/weather/blizzard.png differ diff --git a/images/weather/blizzardn.png b/images/weather/blizzardn.png new file mode 100644 index 0000000..18fa272 Binary files /dev/null and b/images/weather/blizzardn.png differ diff --git a/images/weather/blowingsnow.png b/images/weather/blowingsnow.png new file mode 100644 index 0000000..1ccf831 Binary files /dev/null and b/images/weather/blowingsnow.png differ diff --git a/images/weather/blowingsnown.png b/images/weather/blowingsnown.png new file mode 100644 index 0000000..1ccf831 Binary files /dev/null and b/images/weather/blowingsnown.png differ diff --git a/images/weather/chancetstorm.png b/images/weather/chancetstorm.png new file mode 100644 index 0000000..dcaf5cc Binary files /dev/null and b/images/weather/chancetstorm.png differ diff --git a/images/weather/chancetstormn.png b/images/weather/chancetstormn.png new file mode 100644 index 0000000..277854d Binary files /dev/null and b/images/weather/chancetstormn.png differ diff --git a/images/weather/clear.png b/images/weather/clear.png new file mode 100644 index 0000000..d8bba6e Binary files /dev/null and b/images/weather/clear.png differ diff --git a/images/weather/clearn.png b/images/weather/clearn.png new file mode 100644 index 0000000..c696931 Binary files /dev/null and b/images/weather/clearn.png differ diff --git a/images/weather/clearw.png b/images/weather/clearw.png new file mode 100644 index 0000000..dce65f7 Binary files /dev/null and b/images/weather/clearw.png differ diff --git a/images/weather/clearwn.png b/images/weather/clearwn.png new file mode 100644 index 0000000..c696931 Binary files /dev/null and b/images/weather/clearwn.png differ diff --git a/images/weather/cloudy.png b/images/weather/cloudy.png new file mode 100644 index 0000000..22c555c Binary files /dev/null and b/images/weather/cloudy.png differ diff --git a/images/weather/cloudyn.png b/images/weather/cloudyn.png new file mode 100644 index 0000000..22c555c Binary files /dev/null and b/images/weather/cloudyn.png differ diff --git a/images/weather/cloudyw.png b/images/weather/cloudyw.png new file mode 100644 index 0000000..7d22704 Binary files /dev/null and b/images/weather/cloudyw.png differ diff --git a/images/weather/cloudywn.png b/images/weather/cloudywn.png new file mode 100644 index 0000000..7d22704 Binary files /dev/null and b/images/weather/cloudywn.png differ diff --git a/images/weather/drizzle.png b/images/weather/drizzle.png new file mode 100644 index 0000000..389c76a Binary files /dev/null and b/images/weather/drizzle.png differ diff --git a/images/weather/drizzlef.png b/images/weather/drizzlef.png new file mode 100644 index 0000000..b995522 Binary files /dev/null and b/images/weather/drizzlef.png differ diff --git a/images/weather/drizzlen.png b/images/weather/drizzlen.png new file mode 100644 index 0000000..389c76a Binary files /dev/null and b/images/weather/drizzlen.png differ diff --git a/images/weather/dust.png b/images/weather/dust.png new file mode 100644 index 0000000..52581d2 Binary files /dev/null and b/images/weather/dust.png differ diff --git a/images/weather/fair.png b/images/weather/fair.png new file mode 100644 index 0000000..cb44dc6 Binary files /dev/null and b/images/weather/fair.png differ diff --git a/images/weather/fairn.png b/images/weather/fairn.png new file mode 100644 index 0000000..5c576bb Binary files /dev/null and b/images/weather/fairn.png differ diff --git a/images/weather/fairw.png b/images/weather/fairw.png new file mode 100644 index 0000000..92979ff Binary files /dev/null and b/images/weather/fairw.png differ diff --git a/images/weather/fairwn.png b/images/weather/fairwn.png new file mode 100644 index 0000000..c5e632d Binary files /dev/null and b/images/weather/fairwn.png differ diff --git a/images/weather/fdrizzle.png b/images/weather/fdrizzle.png new file mode 100644 index 0000000..66b2bc6 Binary files /dev/null and b/images/weather/fdrizzle.png differ diff --git a/images/weather/fdrizzlen.png b/images/weather/fdrizzlen.png new file mode 100644 index 0000000..66b2bc6 Binary files /dev/null and b/images/weather/fdrizzlen.png differ diff --git a/images/weather/flurries.png b/images/weather/flurries.png new file mode 100644 index 0000000..722d509 Binary files /dev/null and b/images/weather/flurries.png differ diff --git a/images/weather/flurriesn.png b/images/weather/flurriesn.png new file mode 100644 index 0000000..722d509 Binary files /dev/null and b/images/weather/flurriesn.png differ diff --git a/images/weather/flurriesw.png b/images/weather/flurriesw.png new file mode 100644 index 0000000..4579f8a Binary files /dev/null and b/images/weather/flurriesw.png differ diff --git a/images/weather/flurrieswn.png b/images/weather/flurrieswn.png new file mode 100644 index 0000000..4579f8a Binary files /dev/null and b/images/weather/flurrieswn.png differ diff --git a/images/weather/fog.png b/images/weather/fog.png new file mode 100644 index 0000000..e08acad Binary files /dev/null and b/images/weather/fog.png differ diff --git a/images/weather/fogn.png b/images/weather/fogn.png new file mode 100644 index 0000000..e08acad Binary files /dev/null and b/images/weather/fogn.png differ diff --git a/images/weather/freezingrain.png b/images/weather/freezingrain.png new file mode 100644 index 0000000..6cabd85 Binary files /dev/null and b/images/weather/freezingrain.png differ diff --git a/images/weather/freezingrainn.png b/images/weather/freezingrainn.png new file mode 100644 index 0000000..6cabd85 Binary files /dev/null and b/images/weather/freezingrainn.png differ diff --git a/images/weather/hazy.png b/images/weather/hazy.png new file mode 100644 index 0000000..af54b9a Binary files /dev/null and b/images/weather/hazy.png differ diff --git a/images/weather/hazyn.png b/images/weather/hazyn.png new file mode 100644 index 0000000..e65e3c9 Binary files /dev/null and b/images/weather/hazyn.png differ diff --git a/images/weather/mcloudy.png b/images/weather/mcloudy.png new file mode 100644 index 0000000..7e379bb Binary files /dev/null and b/images/weather/mcloudy.png differ diff --git a/images/weather/mcloudyn.png b/images/weather/mcloudyn.png new file mode 100644 index 0000000..03c4004 Binary files /dev/null and b/images/weather/mcloudyn.png differ diff --git a/images/weather/mcloudyr.png b/images/weather/mcloudyr.png new file mode 100644 index 0000000..b3ce77c Binary files /dev/null and b/images/weather/mcloudyr.png differ diff --git a/images/weather/mcloudyrn.png b/images/weather/mcloudyrn.png new file mode 100644 index 0000000..920d14c Binary files /dev/null and b/images/weather/mcloudyrn.png differ diff --git a/images/weather/mcloudyrw.png b/images/weather/mcloudyrw.png new file mode 100644 index 0000000..e07695b Binary files /dev/null and b/images/weather/mcloudyrw.png differ diff --git a/images/weather/mcloudyrwn.png b/images/weather/mcloudyrwn.png new file mode 100644 index 0000000..5353e37 Binary files /dev/null and b/images/weather/mcloudyrwn.png differ diff --git a/images/weather/mcloudys.png b/images/weather/mcloudys.png new file mode 100644 index 0000000..e21149b Binary files /dev/null and b/images/weather/mcloudys.png differ diff --git a/images/weather/mcloudysfn.png b/images/weather/mcloudysfn.png new file mode 100644 index 0000000..9e241dd Binary files /dev/null and b/images/weather/mcloudysfn.png differ diff --git a/images/weather/mcloudysfw.png b/images/weather/mcloudysfw.png new file mode 100644 index 0000000..de588d0 Binary files /dev/null and b/images/weather/mcloudysfw.png differ diff --git a/images/weather/mcloudysfwn.png b/images/weather/mcloudysfwn.png new file mode 100644 index 0000000..338ebe8 Binary files /dev/null and b/images/weather/mcloudysfwn.png differ diff --git a/images/weather/mcloudysn.png b/images/weather/mcloudysn.png new file mode 100644 index 0000000..6124f24 Binary files /dev/null and b/images/weather/mcloudysn.png differ diff --git a/images/weather/mcloudysw.png b/images/weather/mcloudysw.png new file mode 100644 index 0000000..b6060f2 Binary files /dev/null and b/images/weather/mcloudysw.png differ diff --git a/images/weather/mcloudyswn.png b/images/weather/mcloudyswn.png new file mode 100644 index 0000000..f59849d Binary files /dev/null and b/images/weather/mcloudyswn.png differ diff --git a/images/weather/mcloudyt.png b/images/weather/mcloudyt.png new file mode 100644 index 0000000..3d4eeb4 Binary files /dev/null and b/images/weather/mcloudyt.png differ diff --git a/images/weather/mcloudytn.png b/images/weather/mcloudytn.png new file mode 100644 index 0000000..045fc7b Binary files /dev/null and b/images/weather/mcloudytn.png differ diff --git a/images/weather/mcloudytw.png b/images/weather/mcloudytw.png new file mode 100644 index 0000000..d79707c Binary files /dev/null and b/images/weather/mcloudytw.png differ diff --git a/images/weather/mcloudytwn.png b/images/weather/mcloudytwn.png new file mode 100644 index 0000000..5c46e7c Binary files /dev/null and b/images/weather/mcloudytwn.png differ diff --git a/images/weather/mcloudyw.png b/images/weather/mcloudyw.png new file mode 100644 index 0000000..12efca7 Binary files /dev/null and b/images/weather/mcloudyw.png differ diff --git a/images/weather/mcloudywn.png b/images/weather/mcloudywn.png new file mode 100644 index 0000000..4667249 Binary files /dev/null and b/images/weather/mcloudywn.png differ diff --git a/images/weather/na.png b/images/weather/na.png new file mode 100644 index 0000000..172739d Binary files /dev/null and b/images/weather/na.png differ diff --git a/images/weather/pcloudy.png b/images/weather/pcloudy.png new file mode 100644 index 0000000..a56717b Binary files /dev/null and b/images/weather/pcloudy.png differ diff --git a/images/weather/pcloudyn.png b/images/weather/pcloudyn.png new file mode 100644 index 0000000..4c1c357 Binary files /dev/null and b/images/weather/pcloudyn.png differ diff --git a/images/weather/pcloudyr.png b/images/weather/pcloudyr.png new file mode 100644 index 0000000..0b5434b Binary files /dev/null and b/images/weather/pcloudyr.png differ diff --git a/images/weather/pcloudyrn.png b/images/weather/pcloudyrn.png new file mode 100644 index 0000000..1520782 Binary files /dev/null and b/images/weather/pcloudyrn.png differ diff --git a/images/weather/pcloudyrw.png b/images/weather/pcloudyrw.png new file mode 100644 index 0000000..890a821 Binary files /dev/null and b/images/weather/pcloudyrw.png differ diff --git a/images/weather/pcloudyrwn.png b/images/weather/pcloudyrwn.png new file mode 100644 index 0000000..1b6b189 Binary files /dev/null and b/images/weather/pcloudyrwn.png differ diff --git a/images/weather/pcloudys.png b/images/weather/pcloudys.png new file mode 100644 index 0000000..a41145d Binary files /dev/null and b/images/weather/pcloudys.png differ diff --git a/images/weather/pcloudysf.png b/images/weather/pcloudysf.png new file mode 100644 index 0000000..a41145d Binary files /dev/null and b/images/weather/pcloudysf.png differ diff --git a/images/weather/pcloudysfn.png b/images/weather/pcloudysfn.png new file mode 100644 index 0000000..4bba412 Binary files /dev/null and b/images/weather/pcloudysfn.png differ diff --git a/images/weather/pcloudysfw.png b/images/weather/pcloudysfw.png new file mode 100644 index 0000000..d74b698 Binary files /dev/null and b/images/weather/pcloudysfw.png differ diff --git a/images/weather/pcloudysfwn.png b/images/weather/pcloudysfwn.png new file mode 100644 index 0000000..308490b Binary files /dev/null and b/images/weather/pcloudysfwn.png differ diff --git a/images/weather/pcloudysn.png b/images/weather/pcloudysn.png new file mode 100644 index 0000000..ba5403a Binary files /dev/null and b/images/weather/pcloudysn.png differ diff --git a/images/weather/pcloudysw.png b/images/weather/pcloudysw.png new file mode 100644 index 0000000..8d3d37a Binary files /dev/null and b/images/weather/pcloudysw.png differ diff --git a/images/weather/pcloudyswn.png b/images/weather/pcloudyswn.png new file mode 100644 index 0000000..9c4ae84 Binary files /dev/null and b/images/weather/pcloudyswn.png differ diff --git a/images/weather/pcloudyt.png b/images/weather/pcloudyt.png new file mode 100644 index 0000000..dcaf5cc Binary files /dev/null and b/images/weather/pcloudyt.png differ diff --git a/images/weather/pcloudytn.png b/images/weather/pcloudytn.png new file mode 100644 index 0000000..277854d Binary files /dev/null and b/images/weather/pcloudytn.png differ diff --git a/images/weather/pcloudytw.png b/images/weather/pcloudytw.png new file mode 100644 index 0000000..d1d35f8 Binary files /dev/null and b/images/weather/pcloudytw.png differ diff --git a/images/weather/pcloudytwn.png b/images/weather/pcloudytwn.png new file mode 100644 index 0000000..1688492 Binary files /dev/null and b/images/weather/pcloudytwn.png differ diff --git a/images/weather/pcloudyw.png b/images/weather/pcloudyw.png new file mode 100644 index 0000000..44e83bc Binary files /dev/null and b/images/weather/pcloudyw.png differ diff --git a/images/weather/pcloudywn.png b/images/weather/pcloudywn.png new file mode 100644 index 0000000..4e109e7 Binary files /dev/null and b/images/weather/pcloudywn.png differ diff --git a/images/weather/pm_pcloudy.png b/images/weather/pm_pcloudy.png new file mode 100644 index 0000000..c7435d3 Binary files /dev/null and b/images/weather/pm_pcloudy.png differ diff --git a/images/weather/pm_pcloudyr.png b/images/weather/pm_pcloudyr.png new file mode 100644 index 0000000..6c52612 Binary files /dev/null and b/images/weather/pm_pcloudyr.png differ diff --git a/images/weather/pm_showers.png b/images/weather/pm_showers.png new file mode 100644 index 0000000..c8e25fe Binary files /dev/null and b/images/weather/pm_showers.png differ diff --git a/images/weather/pm_snowshowers.png b/images/weather/pm_snowshowers.png new file mode 100644 index 0000000..39599fe Binary files /dev/null and b/images/weather/pm_snowshowers.png differ diff --git a/images/weather/pm_tstorm.png b/images/weather/pm_tstorm.png new file mode 100644 index 0000000..be1d833 Binary files /dev/null and b/images/weather/pm_tstorm.png differ diff --git a/images/weather/rain.png b/images/weather/rain.png new file mode 100644 index 0000000..53d8d52 Binary files /dev/null and b/images/weather/rain.png differ diff --git a/images/weather/rainandsnow.png b/images/weather/rainandsnow.png new file mode 100644 index 0000000..23dd0b8 Binary files /dev/null and b/images/weather/rainandsnow.png differ diff --git a/images/weather/rainandsnown.png b/images/weather/rainandsnown.png new file mode 100644 index 0000000..23dd0b8 Binary files /dev/null and b/images/weather/rainandsnown.png differ diff --git a/images/weather/rainn.png b/images/weather/rainn.png new file mode 100644 index 0000000..53d8d52 Binary files /dev/null and b/images/weather/rainn.png differ diff --git a/images/weather/raintosnow.png b/images/weather/raintosnow.png new file mode 100644 index 0000000..6f56150 Binary files /dev/null and b/images/weather/raintosnow.png differ diff --git a/images/weather/raintosnown.png b/images/weather/raintosnown.png new file mode 100644 index 0000000..6f56150 Binary files /dev/null and b/images/weather/raintosnown.png differ diff --git a/images/weather/rainw.png b/images/weather/rainw.png new file mode 100644 index 0000000..baa5c2e Binary files /dev/null and b/images/weather/rainw.png differ diff --git a/images/weather/showers.png b/images/weather/showers.png new file mode 100644 index 0000000..de4eab2 Binary files /dev/null and b/images/weather/showers.png differ diff --git a/images/weather/showersn.png b/images/weather/showersn.png new file mode 100644 index 0000000..de4eab2 Binary files /dev/null and b/images/weather/showersn.png differ diff --git a/images/weather/showersw.png b/images/weather/showersw.png new file mode 100644 index 0000000..60bf9da Binary files /dev/null and b/images/weather/showersw.png differ diff --git a/images/weather/showerswn.png b/images/weather/showerswn.png new file mode 100644 index 0000000..60bf9da Binary files /dev/null and b/images/weather/showerswn.png differ diff --git a/images/weather/sleet.png b/images/weather/sleet.png new file mode 100644 index 0000000..bb70907 Binary files /dev/null and b/images/weather/sleet.png differ diff --git a/images/weather/sleetn.png b/images/weather/sleetn.png new file mode 100644 index 0000000..bb70907 Binary files /dev/null and b/images/weather/sleetn.png differ diff --git a/images/weather/sleetsnow.png b/images/weather/sleetsnow.png new file mode 100644 index 0000000..40732fd Binary files /dev/null and b/images/weather/sleetsnow.png differ diff --git a/images/weather/smoke.png b/images/weather/smoke.png new file mode 100644 index 0000000..1fe4301 Binary files /dev/null and b/images/weather/smoke.png differ diff --git a/images/weather/snow.png b/images/weather/snow.png new file mode 100644 index 0000000..fd3bd95 Binary files /dev/null and b/images/weather/snow.png differ diff --git a/images/weather/snown.png b/images/weather/snown.png new file mode 100644 index 0000000..fd3bd95 Binary files /dev/null and b/images/weather/snown.png differ diff --git a/images/weather/snowshowers.png b/images/weather/snowshowers.png new file mode 100644 index 0000000..cb9d614 Binary files /dev/null and b/images/weather/snowshowers.png differ diff --git a/images/weather/snowshowersn.png b/images/weather/snowshowersn.png new file mode 100644 index 0000000..cb9d614 Binary files /dev/null and b/images/weather/snowshowersn.png differ diff --git a/images/weather/snowshowersw.png b/images/weather/snowshowersw.png new file mode 100644 index 0000000..81c991c Binary files /dev/null and b/images/weather/snowshowersw.png differ diff --git a/images/weather/snowshowerswn.png b/images/weather/snowshowerswn.png new file mode 100644 index 0000000..81c991c Binary files /dev/null and b/images/weather/snowshowerswn.png differ diff --git a/images/weather/snowtorain.png b/images/weather/snowtorain.png new file mode 100644 index 0000000..835c3f7 Binary files /dev/null and b/images/weather/snowtorain.png differ diff --git a/images/weather/snowtorainn.png b/images/weather/snowtorainn.png new file mode 100644 index 0000000..835c3f7 Binary files /dev/null and b/images/weather/snowtorainn.png differ diff --git a/images/weather/snoww.png b/images/weather/snoww.png new file mode 100644 index 0000000..6cd264e Binary files /dev/null and b/images/weather/snoww.png differ diff --git a/images/weather/snowwn.png b/images/weather/snowwn.png new file mode 100644 index 0000000..6cd264e Binary files /dev/null and b/images/weather/snowwn.png differ diff --git a/images/weather/sunny.png b/images/weather/sunny.png new file mode 100644 index 0000000..d8bba6e Binary files /dev/null and b/images/weather/sunny.png differ diff --git a/images/weather/sunnyn.png b/images/weather/sunnyn.png new file mode 100644 index 0000000..c696931 Binary files /dev/null and b/images/weather/sunnyn.png differ diff --git a/images/weather/sunnyw.png b/images/weather/sunnyw.png new file mode 100644 index 0000000..dce65f7 Binary files /dev/null and b/images/weather/sunnyw.png differ diff --git a/images/weather/sunnywn.png b/images/weather/sunnywn.png new file mode 100644 index 0000000..c696931 Binary files /dev/null and b/images/weather/sunnywn.png differ diff --git a/images/weather/tstorm.png b/images/weather/tstorm.png new file mode 100644 index 0000000..c316829 Binary files /dev/null and b/images/weather/tstorm.png differ diff --git a/images/weather/tstormn.png b/images/weather/tstormn.png new file mode 100644 index 0000000..c316829 Binary files /dev/null and b/images/weather/tstormn.png differ diff --git a/images/weather/tstormsw.png b/images/weather/tstormsw.png new file mode 100644 index 0000000..5f08bc8 Binary files /dev/null and b/images/weather/tstormsw.png differ diff --git a/images/weather/tstormswn.png b/images/weather/tstormswn.png new file mode 100644 index 0000000..5f08bc8 Binary files /dev/null and b/images/weather/tstormswn.png differ diff --git a/images/weather/tstormw.png b/images/weather/tstormw.png new file mode 100644 index 0000000..5f08bc8 Binary files /dev/null and b/images/weather/tstormw.png differ diff --git a/images/weather/tstormwn.png b/images/weather/tstormwn.png new file mode 100644 index 0000000..5f08bc8 Binary files /dev/null and b/images/weather/tstormwn.png differ diff --git a/images/weather/wind.png b/images/weather/wind.png new file mode 100644 index 0000000..f4b9ba2 Binary files /dev/null and b/images/weather/wind.png differ diff --git a/images/weather/wintrymix.png b/images/weather/wintrymix.png new file mode 100644 index 0000000..0fe36e6 Binary files /dev/null and b/images/weather/wintrymix.png differ diff --git a/images/weather/wintrymixn.png b/images/weather/wintrymixn.png new file mode 100644 index 0000000..0fe36e6 Binary files /dev/null and b/images/weather/wintrymixn.png differ diff --git a/interface/Panel.lua b/interface/Panel.lua new file mode 100644 index 0000000..00f7d06 --- /dev/null +++ b/interface/Panel.lua @@ -0,0 +1,34 @@ +local Widget = require 'Widget' +local FillRect = require 'FillRect' + +local PAD_X = 20 +local PAD_Y = 10 + +local left = Widget.Panel{ + x = CONSTRUCTION_GLOBAL.LEFT_X - PAD_X, + y = CONSTRUCTION_GLOBAL.TOP_Y - PAD_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH + PAD_X * 2, + height = CONSTRUCTION_GLOBAL.SIDE_HEIGHT + PAD_Y * 2, +} +local center = Widget.Panel{ + x = CONSTRUCTION_GLOBAL.CENTER_X - PAD_X, + y = CONSTRUCTION_GLOBAL.TOP_Y - PAD_Y, + width = CONSTRUCTION_GLOBAL.CENTER_WIDTH + PAD_X * 2, + height = CONSTRUCTION_GLOBAL.CENTER_HEIGHT + PAD_Y * 2, +} +local right = Widget.Panel{ + x = CONSTRUCTION_GLOBAL.RIGHT_X - PAD_X, + y = CONSTRUCTION_GLOBAL.TOP_Y - PAD_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH + PAD_X * 2, + height = CONSTRUCTION_GLOBAL.SIDE_HEIGHT + PAD_Y * 2, +} + +Widget = nil + +local draw = function(cr) + FillRect.draw(left, cr) + FillRect.draw(center, cr) + FillRect.draw(right, cr) +end + +return draw diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..1886f83 --- /dev/null +++ b/main.lua @@ -0,0 +1,150 @@ +--CONVENTIONS: +--0: true, 1: false + +local ABS_PATH = os.getenv('CONKY_LUA_HOME') + +package.path = ABS_PATH..'/?.lua;'.. + ABS_PATH..'/interface/?.lua;'.. + ABS_PATH..'/module/?.lua;'.. + ABS_PATH..'/func/?.lua;'.. + ABS_PATH..'/super/?.lua;'.. + ABS_PATH..'/schema/?.lua;'.. + ABS_PATH..'/widget/?.lua;'.. + ABS_PATH..'/widget/arc/?.lua;'.. + ABS_PATH..'/widget/text/?.lua;'.. + ABS_PATH..'/widget/plot/?.lua;'.. + ABS_PATH..'/widget/rect/?.lua;'.. + ABS_PATH..'/widget/poly/?.lua;'.. + ABS_PATH..'/widget/image/?.lua;' + +local UPDATE_FREQUENCY = 1 --Hz + +CONSTRUCTION_GLOBAL = { + UPDATE_INTERVAL = 1 / UPDATE_FREQUENCY, + LEFT_X = 30, + CENTER_X = 376, + RIGHT_X = 1045, + TOP_Y = 21, + SIDE_WIDTH = 300, + SIDE_HEIGHT = 709, + CENTER_WIDTH = 623, + CENTER_HEIGHT = 154, + ABS_PATH = ABS_PATH +} + +ABS_PATH = nil + +conky_set_update_interval(CONSTRUCTION_GLOBAL.UPDATE_INTERVAL) + +require 'imlib2' +require 'cairo' + +local util = require 'util' +local Panel = require 'Panel' +local System = require 'System' +local Network = require 'Network' +local Processor = require 'Processor' +local FileSystem = require 'FileSystem' +local Pacman = require 'Pacman' +local ReadWrite = require 'ReadWrite' +local Memory = require 'Memory' +--~ local USB = require 'USB' +--~ local Remote = require 'Remote' +local Weather = require 'Weather' + +local updates = -2 + +local unrequire = function(m) + package.loaded[m] = nil + _G[m] = nil +end + +unrequire('Super') +unrequire('Color') +unrequire('Gradient') + +unrequire = nil + +CONSTRUCTION_GLOBAL = nil + +local _CAIRO_XLIB_SURFACE_CREATE = cairo_xlib_surface_create +local _CAIRO_CREATE = cairo_create +local _CAIRO_SURFACE_DESTROY = cairo_surface_destroy +local _CAIRO_DESTROY = cairo_destroy +local _COLLECTGARBAGE = collectgarbage +local _OS_EXECUTE = os.execute + +local using_ac = function() + if util.conky('${acpiacadapter AC}') == 'on-line' then return 0 end +end + +local current_last_log_entry = util.execute_cmd('tail -1 /var/log/pacman.log') + +local check_if_log_changed = function() + local new_last_log_entry = util.execute_cmd('tail -1 /var/log/pacman.log') + if new_last_log_entry == current_last_log_entry then return 1 end + current_last_log_entry = new_last_log_entry + return 0 +end + +_OS_EXECUTE('set_conky_interface.sh 0') +local current_interface = 0 + +local check_interface = function() + local next_interface = util.read_file('/tmp/conky_interface', nil, '*n') + + if next_interface ~= '' then + if next_interface == current_interface then return 1 end + current_interface = next_interface + return 0 + else + _OS_EXECUTE('set_conky_interface.sh 0') + current_interface = 0 + return 0 + end +end + +function conky_main() + local cw = conky_window + if not cw then return end + --~ print(cw.width, cw.height) ###USE THIS TO GET WIDTH AND HEIGHT OF WINDOW + local cs = _CAIRO_XLIB_SURFACE_CREATE(cw.display, cw.drawable, cw.visual, 1377, 778) + local cr = _CAIRO_CREATE(cs) + + updates = updates + 1 + + local t1 = updates % (UPDATE_FREQUENCY * 10) + + local t2 + if using_ac() then + t2 = updates % (UPDATE_FREQUENCY * 60) + else + t2 = updates % (UPDATE_FREQUENCY * 300) + end + + local log_changed = 1 + if t2 == 0 then log_changed = check_if_log_changed() end + local interface_changed = check_interface() + + Panel(cr) + + --interface 0 + System(cr, current_interface, log_changed) + Network(cr, current_interface, UPDATE_FREQUENCY) + Processor(cr, current_interface) + FileSystem(cr, current_interface, t1) + Pacman(cr, current_interface, log_changed) + ReadWrite(cr, current_interface, UPDATE_FREQUENCY) + Memory(cr, current_interface) + + --interface 1 + --~ USB(cr, current_interface) + --~ Remote(cr, current_interface, t1) + + --interface 1 + Weather(cr, current_interface, interface_changed) + + _CAIRO_SURFACE_DESTROY(cs) + _CAIRO_DESTROY(cr) + _COLLECTGARBAGE() +end diff --git a/module/FileSystem.lua b/module/FileSystem.lua new file mode 100644 index 0000000..d397498 --- /dev/null +++ b/module/FileSystem.lua @@ -0,0 +1,115 @@ +local _CR = require 'CR' +local Widget = require 'Widget' +local Text = require 'Text' +local CriticalText = require 'CriticalText' +local Line = require 'Line' +local TextColumn = require 'TextColumn' +local CompoundBar = require 'CompoundBar' +local util = require 'util' +local schema = require 'default_patterns' + +local _PAIRS = pairs +local _STRING_MATCH = string.match + +local FS_PATHS = {'/', '/boot', '/var', '/home', '/mnt/data', '/usr/local/opt'} +local FS_NUM = #FS_PATHS +local FS_REGEX = '^([%d%p]-)(%a+)' + +--construction params +local SPACING = 20 +local TEXT_WIDTH = 200 +local BAR_PAD = 20 + +local header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.CENTER_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.CENTER_WIDTH, + header = "FILE SYSTEMS" +} + +local HEADER_BOTTOM_Y = header.bottom_y + +local labels = Widget.TextColumn{ + x = CONSTRUCTION_GLOBAL.CENTER_X, + y = HEADER_BOTTOM_Y, + spacing = SPACING, + 'root', + 'boot', + 'var', + 'home', + 'data', + 'lopt' +} + +local totals = {} + +for i = 1, FS_NUM do + totals[i] = Widget.CriticalText{ + x = CONSTRUCTION_GLOBAL.CENTER_X + TEXT_WIDTH, + y = HEADER_BOTTOM_Y + (i - 1) * SPACING, + x_align = 'right', + text_color = schema.blue, + } +end + +local units = {} +local conky_used = {} +local conky_used_perc = {} + +for i, v in _PAIRS(FS_PATHS) do + local size, unit = _STRING_MATCH(util.conky('${fs_size '..v..'}'), FS_REGEX) + totals[i].append_end = ' / '..size..' ('..unit..')' + units[i] = unit + conky_used[i] = '${fs_used '..v..'}' + conky_used_perc[i] = '${fs_used_perc '..v..'}' +end + +local bars = Widget.CompoundBar{ + x = CONSTRUCTION_GLOBAL.CENTER_X + TEXT_WIDTH + BAR_PAD, + y = HEADER_BOTTOM_Y, + length = CONSTRUCTION_GLOBAL.CENTER_WIDTH - (TEXT_WIDTH + BAR_PAD), + spacing = SPACING, + num_bars = FS_NUM, + critical_limit = '>0.8' +} + +Widget = nil +_PAIRS = nil +schema = nil + +SPACING = nil +TEXT_WIDTH = nil +BAR_PAD = nil +FS_PATHS = nil +HEADER_BOTTOM_Y = nil + +local __update = function(cr) + for i = 1, FS_NUM do + local value, unit = _STRING_MATCH(util.conky(conky_used[i]), FS_REGEX) + local percent = util.conky_numeric(conky_used_perc[i]) + local force = 1 + if percent > 80 then force = 0 end + CriticalText.set(totals[i], cr, util.precision_convert_bytes(value, unit, units[i], 3), force) + CompoundBar.set(bars, i, percent * 0.01) + end +end + +__update(_CR) + +_CR = nil + +local draw = function(cr, current_interface, trigger) + if trigger == 0 then __update(cr) end + + if current_interface == 0 then + Text.draw(header.text, cr) + Line.draw(header.underline, cr) + TextColumn.draw(labels, cr) + for i = 1, FS_NUM do + CriticalText.draw(totals[i], cr) + end + CompoundBar.draw(bars, cr) + end +end + +return draw diff --git a/module/Memory.lua b/module/Memory.lua new file mode 100644 index 0000000..88e6e2c --- /dev/null +++ b/module/Memory.lua @@ -0,0 +1,234 @@ +local Widget = require 'Widget' +local Arc = require 'Arc' +local Dial = require 'Dial' +local CriticalText = require 'CriticalText' +local Text = require 'Text' +local TextColumn = require 'TextColumn' +local Line = require 'Line' +local LabelPlot = require 'LabelPlot' +local Table = require 'Table' +local util = require 'util' +local schema = require 'default_patterns' + +local _STRING_MATCH = string.match +local _MATH_RAD = math.rad + +local _CAIRO_PATH_DESTROY = cairo_path_destroy + +local MODULE_Y = 397 + +local MEM_TOTAL = tonumber(util.read_file('/proc/meminfo', 'MemTotal:%s+(%d+)')) --in kB + +local DIAL_RADIUS = 32 +local DIAL_THETA0 = 90 +local DIAL_THETA1 = 360 + +local TABLE_CONKY = {} +for c = 1, 3 do TABLE_CONKY[c] = {} end +for r = 1, 5 do TABLE_CONKY[1][r] = '${top_mem name '..r..'}' end +for r = 1, 5 do TABLE_CONKY[2][r] = '${top_mem pid '..r..'}' end +for r = 1, 5 do TABLE_CONKY[3][r] = '${top_mem mem '..r..'}' end + +--construction params +local DIAL_THICKNESS = 8 +local DIAL_SPACING = 1 +local TEXT_Y_OFFSET = 7 +local TEXT_LEFT_X_OFFSET = 30 +local TEXT_SPACING = 20 +local SEPARATOR_SPACING = 15 +local PLOT_SECTION_BREAK = 30 +local PLOT_HEIGHT = 56 +local TABLE_SECTION_BREAK = 20 +local TABLE_HEIGHT = 114 + +local header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = MODULE_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "MEMORY" +} + +local HEADER_BOTTOM_Y = header.bottom_y + +--don't nil these +local DIAL_X = CONSTRUCTION_GLOBAL.RIGHT_X + DIAL_RADIUS + DIAL_THICKNESS * 0.5 +local DIAL_Y = HEADER_BOTTOM_Y + DIAL_RADIUS + DIAL_THICKNESS * 0.5 + +local dial = Widget.Dial{ + x = DIAL_X, + y = DIAL_Y, + radius = DIAL_RADIUS, + thickness = DIAL_THICKNESS, + critical_limit = '>0.8' +} +local cache_arc = Widget.Arc{ + x = DIAL_X, + y = DIAL_Y, + radius = DIAL_RADIUS, + thickness = DIAL_THICKNESS, + arc_pattern = schema.purple_rounded +} + +local total_used = Widget.CriticalText{ + x = DIAL_X, + y = DIAL_Y, + x_align = 'center', + y_align = 'center', + append_end = '%' +} +local inner_ring = Widget.Arc{ + x = DIAL_X, + y = DIAL_Y, + radius = DIAL_RADIUS - DIAL_THICKNESS / 2 - 2, + theta0 = 0, + theta1 = 360 +} + +local LINE_1_Y = HEADER_BOTTOM_Y + TEXT_Y_OFFSET +local TEXT_LEFT_X = CONSTRUCTION_GLOBAL.RIGHT_X + DIAL_RADIUS * 2 + TEXT_LEFT_X_OFFSET +local RIGHT_X = CONSTRUCTION_GLOBAL.RIGHT_X + CONSTRUCTION_GLOBAL.SIDE_WIDTH + +local swap= { + label = Widget.Text{ + x = TEXT_LEFT_X, + y = LINE_1_Y, + spacing = TEXT_SPACING, + text = 'Swap Usage' + }, + percent = Widget.CriticalText{ + x = RIGHT_X, + y = LINE_1_Y, + x_align = 'right', + append_end = ' %', + }, +} + +local cache = { + labels = Widget.TextColumn{ + x = TEXT_LEFT_X, + y = LINE_1_Y + TEXT_SPACING, + spacing = TEXT_SPACING, + 'Page Cache', + 'Buffers', + 'Kernel Slab' + }, + percents = Widget.TextColumn{ + x = RIGHT_X, + y = LINE_1_Y + TEXT_SPACING, + x_align = 'right', + append_end = ' %', + text_color = schema.purple, + '', + '', + '' + }, +} + +local PLOT_Y = PLOT_SECTION_BREAK + HEADER_BOTTOM_Y + DIAL_RADIUS * 2 + +local plot = Widget.LabelPlot{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = PLOT_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = PLOT_HEIGHT +} + +local TABLE_Y = PLOT_Y + PLOT_HEIGHT + TABLE_SECTION_BREAK + +local tbl = Widget.Table{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = TABLE_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = TABLE_HEIGHT, + 'Name', + 'PID', + 'Mem (%)' +} + +DIAL_THETA0 = _MATH_RAD(DIAL_THETA0) +DIAL_THETA1 = _MATH_RAD(DIAL_THETA1) + +local __update = function(cr) + local MEM_TOTAL = MEM_TOTAL + + local round = util.round + local precision_round_to_string = util.precision_round_to_string + local glob = util.read_file('/proc/meminfo') --kB + + --see source for "free" for formulas and stuff ;) + + local swap_free = _STRING_MATCH(glob, 'SwapFree:%s+(%d+)' ) + local swap_total = _STRING_MATCH(glob, 'SwapTotal:%s+(%d+)') + local page_cache = _STRING_MATCH(glob, 'Cached:%s+(%d+)' ) + local slab = _STRING_MATCH(glob, 'Slab:%s+(%d+)' ) + local buffers = _STRING_MATCH(glob, 'Buffers:%s+(%d+)' ) + local free = _STRING_MATCH(glob, 'MemFree:%s+(%d+)' ) + + local used_percent = util.round((MEM_TOTAL - free - page_cache - buffers - slab) / MEM_TOTAL, 2) + + Dial.set(dial, used_percent) + CriticalText.set(total_used, cr, used_percent * 100) + + local cache_theta = (DIAL_THETA0 - DIAL_THETA1) / MEM_TOTAL * free + DIAL_THETA1 + _CAIRO_PATH_DESTROY(cache_arc.path) + cache_arc.path = Arc.create_path(DIAL_X, DIAL_Y, DIAL_RADIUS, dial.dial_angle, cache_theta) + + CriticalText.set(swap.percent, cr, precision_round_to_string((swap_total - swap_free) / swap_total * 100)) + + local percents = cache.percents + TextColumn.set(percents, cr, 1, precision_round_to_string(page_cache / MEM_TOTAL * 100)) + TextColumn.set(percents, cr, 2, precision_round_to_string(buffers / MEM_TOTAL * 100)) + TextColumn.set(percents, cr, 3, precision_round_to_string(slab / MEM_TOTAL * 100)) + + LabelPlot.update(plot, used_percent) + + for c = 1, 3 do + local column = TABLE_CONKY[c] + for r = 1, 5 do + Table.set(tbl, cr, c, r, util.conky(column[r], '(%S+)')) + end + end +end + +Widget = nil +schema = nil +MODULE_Y = nil +DIAL_THICKNESS = nil +DIAL_SPACING = nil +TEXT_Y_OFFSET = nil +TEXT_LEFT_X_OFFSET = nil +TEXT_SPACING = nil +PLOT_SECTION_BREAK = nil +PLOT_HEIGHT = nil +TABLE_SECTION_BREAK = nil +TABLE_HEIGHT = nil +HEADER_BOTTOM_Y = nil +LINE_1_Y = nil +TEXT_LEFT_X = nil +RIGHT_X = nil +PLOT_Y = nil +TABLE_Y = nil + +local draw = function(cr, current_interface) + __update(cr) + + if current_interface == 0 then + Text.draw(header.text, cr) + Line.draw(header.underline, cr) + Dial.draw(dial, cr) + Arc.draw(cache_arc, cr) + Arc.draw(inner_ring, cr) + CriticalText.draw(total_used, cr) + + Text.draw(swap.label, cr) + CriticalText.draw(swap.percent, cr) + TextColumn.draw(cache.labels, cr) + TextColumn.draw(cache.percents, cr) + + LabelPlot.draw(plot, cr) + + Table.draw(tbl, cr) + end +end + +return draw diff --git a/module/Network.lua b/module/Network.lua new file mode 100644 index 0000000..629f130 --- /dev/null +++ b/module/Network.lua @@ -0,0 +1,177 @@ +local Widget = require 'Widget' +local Text = require 'Text' +local Line = require 'Line' +local ScalePlot = require 'ScalePlot' +local util = require 'util' +local schema = require 'default_patterns' + +local _STRING_GMATCH = string.gmatch +local _IO_POPEN = io.popen + +local MODULE_Y = 145 + +--construction params +local PLOT_SEC_BREAK = 20 +local PLOT_HEIGHT = 56 + +local SYSFS_NET = '/sys/class/net/' +local STATS_RX = '/statistics/rx_bytes' +local STATS_TX = '/statistics/tx_bytes' + +local __network_label_function = function(bytes) + local new_unit = util.get_unit(bytes) + + local converted = util.convert_bytes(bytes, 'B', new_unit) + local precision = 0 + if converted < 10 then precision = 1 end + + return util.round_to_string(converted, precision)..' '..new_unit..'/s' +end + +local header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = MODULE_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "NETWORK" +} + +local RIGHT_X = CONSTRUCTION_GLOBAL.LEFT_X + CONSTRUCTION_GLOBAL.SIDE_WIDTH +local DOWNLOAD_PLOT_Y = header.bottom_y + PLOT_SEC_BREAK + +local dnload = { + label = Widget.Text{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = header.bottom_y, + text = 'Download', + }, + speed = Widget.Text{ + x = RIGHT_X, + y = header.bottom_y, + x_align = 'right', + text_color = schema.blue + }, + plot = Widget.ScalePlot{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = DOWNLOAD_PLOT_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = PLOT_HEIGHT, + y_label_func = __network_label_function + } +} + +local UPLOAD_Y = DOWNLOAD_PLOT_Y + PLOT_HEIGHT + PLOT_SEC_BREAK +local UPLOAD_PLOT_Y = UPLOAD_Y + PLOT_SEC_BREAK + +local upload = { + label = Widget.Text{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = UPLOAD_Y, + text = 'Upload', + }, + speed = Widget.Text{ + x = RIGHT_X, + y = UPLOAD_Y, + x_align = 'right', + text_color = schema.blue + }, + plot = Widget.ScalePlot{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = UPLOAD_PLOT_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = PLOT_HEIGHT, + y_label_func = __network_label_function + } +} + +local interfaces = {} + +local __add_interface = function(iface) + local rx_path = SYSFS_NET..iface..STATS_RX + local tx_path = SYSFS_NET..iface..STATS_TX + + interfaces[iface] = { + rx_path = rx_path, + tx_path = tx_path, + rx_cumulative_bytes = 0, + tx_cumulative_bytes = 0, + prev_rx_cumulative_bytes = util.read_file(rx_path, nil, '*n'), + prev_tx_cumulative_bytes = util.read_file(tx_path, nil, '*n'), + } +end + +for iface in _IO_POPEN('ls -1 '..SYSFS_NET):lines() do + __add_interface(iface) +end + +local __update = function(cr, update_frequency) + local dspeed, uspeed = 0, 0 + local glob = util.execute_cmd('ip route show') + + local rx_bps, tx_bps + + for iface in _STRING_GMATCH(glob, 'default via %d+%.%d+%.%d+%.%d+ dev (%w+) ') do + local current_iface = interfaces[iface] + + if not current_iface then + __add_interface(iface) + current_iface = interfaces[iface] + end + + local new_rx_cumulative_bytes = util.read_file(current_iface.rx_path, nil, '*n') + local new_tx_cumulative_bytes = util.read_file(current_iface.tx_path, nil, '*n') + + rx_bps = (new_rx_cumulative_bytes - current_iface.prev_rx_cumulative_bytes) * update_frequency + tx_bps = (new_tx_cumulative_bytes - current_iface.prev_tx_cumulative_bytes) * update_frequency + + current_iface.prev_rx_cumulative_bytes = new_rx_cumulative_bytes + current_iface.prev_tx_cumulative_bytes = new_tx_cumulative_bytes + + --mask overflow + if rx_bps < 0 then rx_bps = 0 end + if tx_bps < 0 then tx_bps = 0 end + + dspeed = dspeed + rx_bps + uspeed = uspeed + tx_bps + end + + local dspeed_unit = util.get_unit(dspeed) + local uspeed_unit = util.get_unit(uspeed) + + dnload.speed.append_end = ' '..dspeed_unit..'/s' + upload.speed.append_end = ' '..uspeed_unit..'/s' + + Text.set(dnload.speed, cr, util.precision_convert_bytes(dspeed, 'B', dspeed_unit, 3)) + Text.set(upload.speed, cr, util.precision_convert_bytes(uspeed, 'B', uspeed_unit, 3)) + + ScalePlot.update(dnload.plot, cr, dspeed) + ScalePlot.update(upload.plot, cr, uspeed) +end + +Widget = nil +schema = nil +MODULE_Y = nil +PLOT_SEC_BREAK = nil +PLOT_HEIGHT = nil +RIGHT_X = nil +DOWNLOAD_PLOT_Y = nil +UPLOAD_Y = nil +UPLOAD_PLOT_Y = nil + +local draw = function(cr, current_interface, update_frequency) + __update(cr, update_frequency) + + if current_interface == 0 then + Text.draw(header.text, cr) + Line.draw(header.underline, cr) + + Text.draw(dnload.label, cr) + Text.draw(dnload.speed, cr) + ScalePlot.draw(dnload.plot, cr) + + Text.draw(upload.label, cr) + Text.draw(upload.speed, cr) + ScalePlot.draw(upload.plot, cr) + end +end + +return draw diff --git a/module/Pacman.lua b/module/Pacman.lua new file mode 100644 index 0000000..431f02e --- /dev/null +++ b/module/Pacman.lua @@ -0,0 +1,68 @@ +local _CR = require 'CR' +local Widget = require 'Widget' +local Text = require 'Text' +local Line = require 'Line' +local TextColumn = require 'TextColumn' +local util = require 'util' +local schema = require 'default_patterns' + +--construction params +local TEXT_SPACING = 20 + +local header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "PACMAN" +} + +local labels = Widget.TextColumn{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = header.bottom_y, + spacing = TEXT_SPACING, + 'Total', + 'Explicit', + 'Outdated', + 'Orphaned', + 'Local' +} +local info = Widget.TextColumn{ + x = CONSTRUCTION_GLOBAL.RIGHT_X + CONSTRUCTION_GLOBAL.SIDE_WIDTH, + y = header.bottom_y, + spacing = TEXT_SPACING, + x_align = 'right', + text_color = schema.blue, + num_rows = 5, +} + +Widget = nil +schema = nil +TEXT_SPACING = nil + +local __update = function(cr) + local execute_cmd = util.execute_cmd + local line_count = util.line_count + + TextColumn.set(info, cr, 1, line_count(execute_cmd('pacman -Q'))) + TextColumn.set(info, cr, 2, line_count(execute_cmd('pacman -Qe'))) + TextColumn.set(info, cr, 3, line_count(execute_cmd('pacman -Qu'))) + TextColumn.set(info, cr, 4, line_count(execute_cmd('pacman -Qdt'))) + TextColumn.set(info, cr, 5, line_count(execute_cmd('pacman -Qm'))) +end + +__update(_CR) + +_CR = nil + +local draw = function(cr, current_interface, trigger) + if trigger == 0 then __update(cr) end + + if current_interface == 0 then + Text.draw(header.text, cr) + Line.draw(header.underline, cr) + TextColumn.draw(labels, cr) + TextColumn.draw(info, cr) + end +end + +return draw diff --git a/module/Processor.lua b/module/Processor.lua new file mode 100644 index 0000000..87d8d46 --- /dev/null +++ b/module/Processor.lua @@ -0,0 +1,252 @@ +local Widget = require 'Widget' +local Arc = require 'Arc' +local CompoundDial = require 'CompoundDial' +local CriticalText = require 'CriticalText' +local TextColumn = require 'TextColumn' +local Text = require 'Text' +local Line = require 'Line' +local LabelPlot = require 'LabelPlot' +local Table = require 'Table' +local util = require 'util' +local schema = require 'default_patterns' + +local MODULE_Y = 375 + +local CPU_CONKY = { + '${cpu cpu1}', + '${cpu cpu2}', + '${cpu cpu3}', + '${cpu cpu4}', +} + +local TABLE_CONKY = {{}, {}, {}} + +for r = 1, 5 do + TABLE_CONKY[1][r] = '${top name '..r..'}' + TABLE_CONKY[2][r] = '${top pid '..r..'}' + TABLE_CONKY[3][r] = '${top cpu '..r..'}' +end + +--construction params +local DIAL_INNER_RADIUS = 28 +local DIAL_OUTER_RADIUS = 48 +local DIAL_SPACING = 1 + +local TEXT_Y_OFFSET = 15 +local TEXT_LEFT_X_OFFSET = 25 +local TEXT_SPACING = 20 +local SEPARATOR_SPACING = 15 +local PLOT_SECTION_BREAK = 20 +local PLOT_HEIGHT = 56 +local TABLE_SECTION_BREAK = 20 +local TABLE_HEIGHT = 114 + +local header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = MODULE_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "PROCESSOR" +} + +local HEADER_BOTTOM_Y = header.bottom_y + +local DIAL_X = CONSTRUCTION_GLOBAL.LEFT_X + DIAL_OUTER_RADIUS +local DIAL_Y = HEADER_BOTTOM_Y + DIAL_OUTER_RADIUS + +local dials = Widget.CompoundDial{ + x = DIAL_X, + y = DIAL_Y, + inner_radius = DIAL_INNER_RADIUS, + outer_radius = DIAL_OUTER_RADIUS, + spacing = DIAL_SPACING, + num_dials = 4, + critical_limit = '>0.8' +} +local total_load = Widget.CriticalText{ + x = DIAL_X, + y = DIAL_Y, + x_align = 'center', + y_align = 'center', + append_end = '%' +} + +local inner_ring = Widget.Arc{ + x = DIAL_X, + y = DIAL_Y, + radius = DIAL_INNER_RADIUS - 2, + theta0 = 0, + theta1 = 360 +} + +local LINE_1_Y = HEADER_BOTTOM_Y + TEXT_Y_OFFSET +local TEXT_LEFT_X = CONSTRUCTION_GLOBAL.LEFT_X + dials.width + TEXT_LEFT_X_OFFSET +local RIGHT_X = CONSTRUCTION_GLOBAL.LEFT_X + CONSTRUCTION_GLOBAL.SIDE_WIDTH + +local core = { + labels = Widget.TextColumn{ + x = TEXT_LEFT_X, + y = LINE_1_Y, + spacing = TEXT_SPACING, + 'Core 0', + 'Core 1' + }, + temp1 = Widget.CriticalText{ + x = RIGHT_X, + y = LINE_1_Y, + x_align = 'right', + append_end = '°C', + critical_limit = '>86' + }, + temp2 = Widget.CriticalText{ + x = RIGHT_X, + y = LINE_1_Y + TEXT_SPACING, + x_align = 'right', + append_end = '°C', + critical_limit = '>86' + } +} + +local SEP_Y = LINE_1_Y + TEXT_SPACING + SEPARATOR_SPACING + +local separator = Widget.Line{ + p1 = {x = TEXT_LEFT_X, y = SEP_Y}, + p2 = {x = RIGHT_X, y = SEP_Y} +} + +local PROCESS_Y = SEP_Y + SEPARATOR_SPACING + +local process = { + labels = Widget.TextColumn{ + x = TEXT_LEFT_X, + y = PROCESS_Y, + spacing = TEXT_SPACING, + 'R / S', + 'D / T / Z' + }, + totals = Widget.TextColumn{ + x = RIGHT_X, + y = PROCESS_Y, + spacing = TEXT_SPACING, + x_align = 'right', + text_color = schema.blue, + '', + '' + } +} + +local PLOT_Y = PLOT_SECTION_BREAK + HEADER_BOTTOM_Y + dials.height + +local plot = Widget.LabelPlot{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = PLOT_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = PLOT_HEIGHT +} + +local TABLE_Y = PLOT_Y + PLOT_HEIGHT + TABLE_SECTION_BREAK + +local tbl = Widget.Table{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = TABLE_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = TABLE_HEIGHT, + 'Name', + 'PID', + 'CPU (%)' +} + +local __update = function(cr) + local conky = util.conky + local char_count = util.char_count + + local sum = 0 + for i = 1, #CPU_CONKY do + local percent = util.conky_numeric(CPU_CONKY[i]) * 0.01 + CompoundDial.set(dials, i, percent) + sum = sum + percent + end + + local load_percent = util.round(sum * 0.25, 2) + CriticalText.set(total_load, cr, load_percent * 100) + + CriticalText.set(core.temp1, cr, util.round(0.001 * util.read_file( + '/sys/class/thermal/thermal_zone0/temp', nil, '*n'))) + CriticalText.set(core.temp2, cr, util.round(0.001 * util.read_file( + '/sys/class/thermal/thermal_zone1/temp', nil, '*n'))) + + local process_glob = util.execute_cmd('ps -A -o s') + + local running = char_count(process_glob, 'R') + local uninterrupted_sleep = char_count(process_glob, 'D') + local interrupted_sleep = char_count(process_glob, 'S') + local stopped = char_count(process_glob, 'T') + local zombie = char_count(process_glob, 'Z') + + --subtract one b/c ps will always be "running" + running = running - 1 + + local totals = process.totals + TextColumn.set(totals, cr, 1, running..' / '..interrupted_sleep) + TextColumn.set(totals, cr, 2, uninterrupted_sleep..' / '..stopped..' / '..zombie) + + LabelPlot.update(plot, load_percent) + + for c = 1, 3 do + local column = TABLE_CONKY[c] + for r = 1, 5 do + Table.set(tbl, cr, c, r, conky(column[r], '(%S+)')) + end + end +end + +Widget = nil +schema = nil +MODULE_Y = nil +DIAL_INNER_RADIUS = nil +DIAL_OUTER_RADIUS = nil +DIAL_SPACING = nil +TEXT_Y_OFFSET = nil +TEXT_LEFT_X_OFFSET = nil +TEXT_SPACING = nil +SEPARATOR_SPACING = nil +PLOT_SECTION_BREAK = nil +PLOT_HEIGHT = nil +TABLE_SECTION_BREAK = nil +TABLE_HEIGHT = nil +HEADER_BOTTOM_Y = nil +DIAL_X = nil +DIAL_Y = nil +LINE_1_Y = nil +TEXT_LEFT_X = nil +RIGHT_X = nil +SEP_Y = nil +PROCESS_Y = nil +PLOT_Y = nil +TABLE_Y = nil + +local draw = function(cr, current_interface) + __update(cr) + + if current_interface == 0 then + Text.draw(header.text, cr) + Line.draw(header.underline, cr) + CompoundDial.draw(dials, cr) + Arc.draw(inner_ring, cr) + CriticalText.draw(total_load, cr) + + TextColumn.draw(core.labels, cr) + CriticalText.draw(core.temp1, cr) + CriticalText.draw(core.temp2, cr) + + Line.draw(separator, cr) + + TextColumn.draw(process.labels, cr) + TextColumn.draw(process.totals, cr) + + LabelPlot.draw(plot, cr) + + Table.draw(tbl, cr) + end +end + +return draw diff --git a/module/ReadWrite.lua b/module/ReadWrite.lua new file mode 100644 index 0000000..fbe986c --- /dev/null +++ b/module/ReadWrite.lua @@ -0,0 +1,145 @@ +local Widget = require 'Widget' +local Text = require 'Text' +local Line = require 'Line' +local ScalePlot = require 'ScalePlot' +local util = require 'util' +local schema = require 'default_patterns' + +local MODULE_Y = 165 + +local _TONUMBER = tonumber +local _STRING_MATCH = string.match + +local HW_BLOCK_SIZE = 512 --bytes +local STAT_FILE = '/sys/block/sda/stat' +local RW_REGEX = '%s+%d+%s+%d+%s+(%d+)%s+%d+%s+%d+%s+%d+%s+(%d+)' --fields 3 and 7 (sectors read and written) + +--construction params +local PLOT_SEC_BREAK = 20 +local PLOT_HEIGHT = 56 + +local __read_stat_file = function() + local bytes_read, bytes_written = _STRING_MATCH(util.read_file(STAT_FILE), RW_REGEX) + return _TONUMBER(bytes_read) * HW_BLOCK_SIZE, _TONUMBER(bytes_written) * HW_BLOCK_SIZE +end + +local __update_stat = function(cr, stat, cumulative, update_frequency) + local bytes = (cumulative - stat.prev_cumulative) * update_frequency + stat.prev_cumulative = cumulative + + if bytes < 0 then bytes = 0 end --mask wrap + + local unit = util.get_unit(bytes) + + stat.rate.append_end = ' '..unit..'/s' + Text.set(stat.rate, cr, util.precision_convert_bytes(bytes, 'B', unit, 3)) + ScalePlot.update(stat.plot, cr, bytes) +end + +local __io_label_function = function(bytes) + local new_unit = util.get_unit(bytes) + + local converted = util.convert_bytes(bytes, 'B', new_unit) + local precision = 0 + if converted < 10 then precision = 1 end + + return util.round_to_string(converted, precision)..' '..new_unit..'/s' +end + +local header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = MODULE_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "INPUT / OUTPUT" +} + +local HEADER_BOTTOM_Y = header.bottom_y +local RIGHT_X = CONSTRUCTION_GLOBAL.RIGHT_X + CONSTRUCTION_GLOBAL.SIDE_WIDTH +local READS_PLOT_Y = header.bottom_y + PLOT_SEC_BREAK + +local reads = { + label = Widget.Text{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = HEADER_BOTTOM_Y, + text = 'Reads', + }, + rate = Widget.Text{ + x = RIGHT_X, + y = HEADER_BOTTOM_Y, + x_align = 'right', + append_end=' B/s', + text_color = schema.blue + }, + plot = Widget.ScalePlot{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = READS_PLOT_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = PLOT_HEIGHT, + y_label_func = __io_label_function, + } +} + +local WRITE_Y = READS_PLOT_Y + PLOT_HEIGHT + PLOT_SEC_BREAK +local WRITES_PLOT_Y = WRITE_Y + PLOT_SEC_BREAK + +local writes = { + label = Widget.Text{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = WRITE_Y, + text = 'Writes', + }, + rate = Widget.Text{ + x = RIGHT_X, + y = WRITE_Y, + x_align = 'right', + append_end =' B/s', + text_color = schema.blue + }, + plot = Widget.ScalePlot{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = WRITES_PLOT_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = PLOT_HEIGHT, + y_label_func = __io_label_function, + } +} + +Widget = nil +schema = nil +MODULE_Y = nil +PLOT_SEC_BREAK = nil +PLOT_HEIGHT = nil +HEADER_BOTTOM_Y = nil +RIGHT_X = nil +READS_PLOT_Y = nil +WRITE_Y = nil +WRITES_PLOT_Y = nil + +reads.cumulative = 0 +writes.cumulative = 0 +reads.prev_cumulative, writes.prev_cumulative = __read_stat_file() + +local __update = function(cr, update_frequency) + local cumulative_reads, cumulative_writes = __read_stat_file() + __update_stat(cr, reads, cumulative_reads, update_frequency) + __update_stat(cr, writes, cumulative_writes, update_frequency) +end + +local draw = function(cr, current_interface, update_frequency) + __update(cr, update_frequency) + + if current_interface == 0 then + Text.draw(header.text, cr) + Line.draw(header.underline, cr) + + Text.draw(reads.label, cr) + Text.draw(reads.rate, cr) + ScalePlot.draw(reads.plot, cr) + + Text.draw(writes.label, cr) + Text.draw(writes.rate, cr) + ScalePlot.draw(writes.plot, cr) + end +end + +return draw diff --git a/module/Remote.lua b/module/Remote.lua new file mode 100644 index 0000000..2489a9b --- /dev/null +++ b/module/Remote.lua @@ -0,0 +1,280 @@ +local _CR = require 'CR' +local Widget = require 'Widget' +local Text = require 'Text' +local CriticalText = require 'CriticalText' +local Line = require 'Line' +local TextColumn = require 'TextColumn' +local util = require 'util' +local schema = require 'default_patterns' + +local _STRING_FIND = string.find +local _STRING_MATCH = string.match +local _STRING_GMATCH = string.gmatch + +local NUM_ROWS = 12 + +local USERNAME_FORMAT = '(%S+)%s+' +local START_TIME_FORMAT = '%S+%s+%S+%s+%S+%s+(%S+)%s+' + +--construction params +local SPACING = 20 +local SEPARATOR_SPACING = 17 +local MODULE_Y = 285 + +local header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = MODULE_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = 'REMOTE CONNECTIONS' +} + +local FIREWALL_Y = header.bottom_y +local TUNNEL_Y = FIREWALL_Y + SEPARATOR_SPACING * 2 +local SOCKS_Y = TUNNEL_Y + SPACING + SEPARATOR_SPACING * 2 + +local TABLE_Y = SOCKS_Y + SPACING + SEPARATOR_SPACING * 2 +local TABLE_BODY_Y = TABLE_Y + SPACING + 6 + +local RIGHT_X = CONSTRUCTION_GLOBAL.RIGHT_X + CONSTRUCTION_GLOBAL.SIDE_WIDTH + +local firewall = { + label = Widget.Text{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = FIREWALL_Y, + text = 'Firewall Status', + }, + info = Widget.CriticalText{ + x = RIGHT_X, + y = FIREWALL_Y, + x_align = 'right', + text_color = schema.blue, + } +} + +local tunnel = { + labels = Widget.TextColumn{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = TUNNEL_Y, + spacing = SPACING, + 'Tunnel Loaded', + 'Tunnel Running', + }, + info = Widget.TextColumn{ + x = RIGHT_X, + y = TUNNEL_Y, + spacing = SPACING, + x_align = 'right', + text_color = schema.blue, + num_rows = 2, + } +} + +local socks = { + labels = Widget.TextColumn{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = SOCKS_Y, + spacing = SPACING, + 'Socks Loaded', + 'Socks Running', + }, + info = Widget.TextColumn{ + x = RIGHT_X, + y = SOCKS_Y, + spacing = SPACING, + x_align = 'right', + text_color = schema.blue, + num_rows = 2, + } +} + +local tbl = { + headers = { + Widget.Text{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = TABLE_Y, + text = 'Username', + text_color = schema.blue + }, + Widget.Text{ + x = RIGHT_X, + y = TABLE_Y, + text = 'Date / Time', + text_color = schema.blue, + x_align = 'right' + } + }, + columns = { + Widget.TextColumn{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = TABLE_BODY_Y, + spacing = SPACING, + num_rows = NUM_ROWS, + font_size = 10, + max_length = 9 + }, + Widget.TextColumn{ + x = RIGHT_X, + y = TABLE_BODY_Y, + spacing = SPACING, + num_rows = NUM_ROWS, + font_size = 10, + x_align = 'right', + } + } +} + +local separators = { + Widget.Line{ + p1 = { + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = TUNNEL_Y - SEPARATOR_SPACING + }, + p2 = { + x = RIGHT_X, + y = TUNNEL_Y - SEPARATOR_SPACING + } + }, + Widget.Line{ + p1 = { + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = SOCKS_Y - SEPARATOR_SPACING + }, + p2 = { + x = RIGHT_X, + y = SOCKS_Y - SEPARATOR_SPACING + } + }, + Widget.Line{ + p1 = { + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = TABLE_Y - SEPARATOR_SPACING + }, + p2 = { + x = RIGHT_X, + y = TABLE_Y - SEPARATOR_SPACING + } + } +} + +local __set_ssh_status = function(status, obj, cr) + TextColumn.set(obj, cr, 1, _STRING_MATCH(status, '/autossh') and 'Yes' or 'No') + TextColumn.set(obj, cr, 2, _STRING_MATCH(status, '/ssh') and 'Yes' or 'No') +end + +local __parse_log_line = function(log_line) + if not log_line then return end + + local username = _STRING_MATCH(log_line, USERNAME_FORMAT) + local start_date = _STRING_MATCH(log_line, START_TIME_FORMAT) + + local start_time_unix = util.execute_cmd('date --date="'..start_date..'" +"%s"', nil, '*n') + + local start_time_formatted = util.execute_cmd( + 'date --date="'..start_date..'" +"%-m-%-d-%y (%H:%M)"', '(.+)\n') + + if _STRING_FIND(log_line, 'still logged in', 1, true) then + return username, start_time_unix, '*!* '..start_time_formatted..' *!*' + else + return username, start_time_unix, start_time_formatted + end +end + +local __update = function(cr) + __set_ssh_status(util.execute_cmd('systemctl status tunnel'), tunnel.info, cr) + __set_ssh_status(util.execute_cmd('systemctl status socks'), socks.info, cr) + + if util.execute_cmd('systemctl is-active ufw') == 'active\n' then + CriticalText.set(firewall.info, cr, 'Up', 1) + else + CriticalText.set(firewall.info, cr, 'Down', 0) + end + + local next_wtmp = _STRING_GMATCH(util.execute_cmd( + "last -iw --time-format iso | grep -v '0.0.0.0' | head -n -2"), '[^\n]+') + + local next_btmp = _STRING_GMATCH(util.execute_cmd( + "lastb -iw --time-format iso | grep -v '0.0.0.0' | head -n -2"), '[^\n]+') + + local wtmp_username, wtmp_time, wtmp_str = __parse_log_line(next_wtmp()) + local btmp_username, btmp_time, btmp_str = __parse_log_line(next_btmp()) + + local column1 = tbl.columns[1] + local column2 = tbl.columns[2] + + for r = 1, NUM_ROWS do + if wtmp_time and btmp_time then + if wtmp_time > btmp_time then + TextColumn.set(column1, cr, r, wtmp_username) + TextColumn.set(column2, cr, r, wtmp_str) + wtmp_username, wtmp_time, wtmp_str = __parse_log_line(next_wtmp()) + else + TextColumn.set(column1, cr, r, '*'..btmp_username) + TextColumn.set(column2, cr, r, btmp_str) + btmp_username, btmp_time, btmp_str = __parse_log_line(next_btmp()) + end + elseif wtmp_time then + TextColumn.set(column1, cr, r, wtmp_username) + TextColumn.set(column2, cr, r, wtmp_str) + wtmp_username, wtmp_time, wtmp_str = __parse_log_line(next_wtmp()) + elseif btmp_time then + TextColumn.set(column1, cr, r, '*'..btmp_username) + TextColumn.set(column2, cr, r, btmp_str) + btmp_username, btmp_time, btmp_str = __parse_log_line(next_btmp()) + else + TextColumn.set(column1, cr, r, '--') + TextColumn.set(column2, cr, r, '--') + end + end +end + +__update(_CR) + +Widget = nil +schema = nil +SPACING = nil +SEPARATOR_SPACING = nil +MODULE_Y = nil +RIGHT_X = nil +TUNNEL_Y = nil +SOCKS_Y = nil +FIREWALL_Y = nil +TABLE_Y = nil +TABLE_BODY_Y = nil +_CR = nil + +local draw = function(cr, current_interface, trigger) + if trigger == 0 then __update(cr) end + + if current_interface == 1 then + Text.draw(header.text, cr) + Line.draw(header.underline, cr) + + TextColumn.draw(tunnel.labels, cr) + TextColumn.draw(tunnel.info, cr) + + Line.draw(separators[1], cr) + + TextColumn.draw(socks.labels, cr) + TextColumn.draw(socks.info, cr) + + Line.draw(separators[2], cr) + + Text.draw(firewall.label, cr) + CriticalText.draw(firewall.info, cr) + + Line.draw(separators[3], cr) + + local headers = tbl.headers + + Text.draw(headers[1], cr) + Text.draw(headers[2], cr) + + local column1 = tbl.columns[1] + local column2 = tbl.columns[2] + + TextColumn.draw(column1, cr) + TextColumn.draw(column2, cr) + end +end + +return draw diff --git a/module/System.lua b/module/System.lua new file mode 100644 index 0000000..ea22931 --- /dev/null +++ b/module/System.lua @@ -0,0 +1,77 @@ +local _CR = require 'CR' +local Widget = require 'Widget' +local Text = require 'Text' +local Line = require 'Line' +local TextColumn = require 'TextColumn' +local util = require 'util' +local schema = require 'default_patterns' + +local _STRING_MATCH = string.match + +local DATE_REGEX = '%[(%d-)%-(%d-%-%d-)%s' + +local UPGRADE_CMD = "sed -n '/ starting full system upgrade/p' /var/log/pacman.log | tail -1" +local SYNC_CMD = "sed -n '/ synchronizing package lists/p' /var/log/pacman.log | tail -1" + +--construction params +local TEXT_SPACING = 20 + +local header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "SYSTEM" +} + +local labels = Widget.TextColumn{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = header.bottom_y, + spacing = TEXT_SPACING, + 'Kernel', + 'Uptime', + 'Last Upgrade', + 'Last Sync' +} +local info = Widget.TextColumn{ + x = CONSTRUCTION_GLOBAL.LEFT_X + CONSTRUCTION_GLOBAL.SIDE_WIDTH, + y = header.bottom_y, + spacing = TEXT_SPACING, + x_align = 'right', + text_color = schema.blue, + num_rows = 4, +} + +TextColumn.set(info, _CR, 1, util.conky('$kernel')) + +local __update_dates = function(cr) + local yyyy, mm_dd = _STRING_MATCH(util.execute_cmd(UPGRADE_CMD), DATE_REGEX) + TextColumn.set(info, cr, 3, mm_dd..'-'..yyyy) + + yyyy, mm_dd = _STRING_MATCH(util.execute_cmd(SYNC_CMD), DATE_REGEX) + TextColumn.set(info, cr, 4, mm_dd..'-'..yyyy) +end + +local __update_uptime = function(cr) + TextColumn.set(info, cr, 2, util.conky('$uptime')) +end + +__update_dates(_CR) + +Widget = nil +schema = nil +TEXT_SPACING = nil +_CR = nil + +local draw = function(cr, current_interface, trigger) + __update_uptime(cr) + if trigger == 0 then __update_dates(cr) end + + if current_interface == 0 then + Text.draw(header.text, cr) + Line.draw(header.underline, cr) + TextColumn.draw(labels, cr) + TextColumn.draw(info, cr) + end +end + +return draw diff --git a/module/USB.lua b/module/USB.lua new file mode 100644 index 0000000..000d083 --- /dev/null +++ b/module/USB.lua @@ -0,0 +1,422 @@ +local _CR = require 'CR' +local Widget = require 'Widget' +local Text = require 'Text' +local Line = require 'Line' +local TextColumn = require 'TextColumn' +local ScalePlot = require 'ScalePlot' +local util = require 'util' +local schema = require 'default_patterns' + +local _STRING_MATCH = string.match +local _STRING_GMATCH = string.gmatch +local _STRING_GSUB = string.gsub +local _TONUMBER = tonumber +local _OS_EXECUTE = os.execute +local _IO_OPEN = io.open + +local USB_IO_PATH = '/tmp/usbdump.txt' +local USBDUMP_CMD = 'timeout 2 usbdump > '..USB_IO_PATH..' &' +local RIGHT_USB_PCI = '/sys/devices/pci0000:00/0000:00:1c.4/0000:0b:00.0/' +local LEFT_USB_PCI = '/sys/devices/pci0000:00/0000:00:1d.0/' + +local FIND_RIGHT_PORTS = 'find '..RIGHT_USB_PCI..'usb[1-4]/[1-4]-[1,2] -maxdepth 0 -type d 2> /dev/null' +local FIND_PORT_3 = 'find '..LEFT_USB_PCI..'usb[1-4]/[1-4]-1/[1-4]-1.2 -maxdepth 0 -type d 2> /dev/null' +local FIND_SD_SLOT = 'find '..LEFT_USB_PCI..'usb[1-4]/[1-4]-1/[1-4]-1.6 -maxdepth 0 -type d 2> /dev/null' + +local N_COLUMNS = 3 +local N_ROWS = 4 + +local STATUS_PCI_UNLOADED = 'No PCI Module' +local STATUS_USBMON_UNLOADED = 'Usbmon Unloaded' + +--construction params +local SPACING = 20 +local PLOT_SEC_BREAK = 20 +local PLOT_HEIGHT = 56 +local SECTION_PAD = 5 +local DEVICE_HEIGHT = (PLOT_HEIGHT + PLOT_SEC_BREAK + SPACING) * 2 + SPACING + SECTION_PAD + 10 + +local __usb_label_function = function(bytes) + local new_unit = util.get_unit(bytes) + local converted = util.convert_bytes(bytes, 'B', new_unit) + + local precision = 0 + if converted < 10 then precision = 1 end + + return util.round_to_string(converted, precision)..' '..new_unit..'/s' +end + +local __create_io_plot = function(x_offset, y_offset, label) + local obj = { + label = Widget.Text{ + x = x_offset, + y = y_offset, + text = label + }, + speed = Widget.Text{ + x = x_offset + CONSTRUCTION_GLOBAL.SIDE_WIDTH, + y = y_offset, + x_align = 'right', + text_color = schema.blue + }, + plot = Widget.ScalePlot{ + x = x_offset, + y = y_offset + PLOT_SEC_BREAK, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + height = PLOT_HEIGHT, + y_label_func = __usb_label_function + }, + } + + return obj +end + +local __create_device_display = function(x_offset, y_offset, title) + local INPUT_Y = y_offset + SPACING + SECTION_PAD + local OUTPUT_Y = INPUT_Y + SPACING + PLOT_HEIGHT + PLOT_SEC_BREAK + + local obj = { + title = Widget.Text{ + x = x_offset, + y = y_offset, + text = title, + text_color = schema.blue + }, + link_speed = Widget.Text{ + x = x_offset + CONSTRUCTION_GLOBAL.SIDE_WIDTH, + y = y_offset, + x_align = 'right', + text_color = schema.blue + }, + idata = __create_io_plot(x_offset, INPUT_Y, 'Input'), + odata = __create_io_plot(x_offset, OUTPUT_Y, 'Output'), + } + + return obj +end + +local usb = { + header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = 'USB PORTS' + } +} + +local HEADER_BOTTOM_Y = usb.header.bottom_y + +usb[1] = __create_device_display(CONSTRUCTION_GLOBAL.LEFT_X, HEADER_BOTTOM_Y, 'PORT 1') +usb[2] = __create_device_display(CONSTRUCTION_GLOBAL.LEFT_X, HEADER_BOTTOM_Y + DEVICE_HEIGHT, 'PORT 2') +usb[3] = __create_device_display(CONSTRUCTION_GLOBAL.LEFT_X, HEADER_BOTTOM_Y + DEVICE_HEIGHT * 2, 'PORT 3') + +local usbtop = { + header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.CENTER_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.CENTER_WIDTH, + header = 'USB DEVICES' + }, + columns = {}, + separators = {} +} + +HEADER_BOTTOM_Y = usbtop.header.bottom_y + +local HEADERS = {'Port / Slot', 'Device', 'Total I / O'} +local COLUMN_WIDTHS = {150, 323, 150} + +local current_x = CONSTRUCTION_GLOBAL.CENTER_X +local columns = usbtop.columns + +for i = 1, N_COLUMNS do + local column_x = current_x + 0.5 * COLUMN_WIDTHS[i] + + columns[i] = { + header = Widget.Text{ + x = column_x, + y = HEADER_BOTTOM_Y, + x_align = 'center', + text = HEADERS[i], + text_color = schema.blue + }, + column = Widget.TextColumn{ + x = column_x, + y = HEADER_BOTTOM_Y + SPACING + 6, + x_align = 'center', + spacing = SPACING, + num_rows = N_ROWS, + font_size = 10, + max_length = 30 + } + } + current_x = current_x + COLUMN_WIDTHS[i] +end + +current_x = CONSTRUCTION_GLOBAL.CENTER_X +local separators = usbtop.separators + +for i = 1, N_COLUMNS - 1 do + current_x = current_x + COLUMN_WIDTHS[i] + separators[i] = Widget.Line{ + p1 = { + x = current_x, + y = HEADER_BOTTOM_Y + }, + p2 = { + x = current_x, + y = HEADER_BOTTOM_Y + N_ROWS * SPACING + 6 + }, + } +end + +HEADERS = nil +COLUMN_WIDTHS = nil + +current_x = nil +columns = nil +separators = nil + +local card_slot = { + header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "SD CARD SLOT" + } +} + +HEADER_BOTTOM_Y = card_slot.header.bottom_y + +card_slot.port = __create_device_display(CONSTRUCTION_GLOBAL.RIGHT_X, HEADER_BOTTOM_Y, 'Status') + +Widget = nil +schema = nil + +SPACING = nil +PLOT_SEC_BREAK = nil +PLOT_HEIGHT = nil +SECTION_PAD = nil +DEVICE_HEIGHT = nil +HEADER_BOTTOM_Y = nil + +local USBTOP_LIST = {} + +local __draw_device = function(device, cr) + Text.draw(device.title, cr) + Text.draw(device.link_speed, cr) + + local device_plot = device.idata + + Text.draw(device_plot.label, cr) + Text.draw(device_plot.speed, cr) + ScalePlot.draw(device_plot.plot, cr) + + local device_plot = device.odata + + Text.draw(device_plot.label, cr) + Text.draw(device_plot.speed, cr) + ScalePlot.draw(device_plot.plot, cr) +end + +local __populate_active_port = function(port, cr, data_glob, bus_num, path, name) + Text.set(port.link_speed, cr, util.read_file(path..'/speed', nil, '*n') * 0.125 ..' MiB/s') + + local idata_sum = 0 + local odata_sum = 0 + + for devnum_path in _STRING_GMATCH(util.execute_cmd('find '..path..' -name devnum'), '(.-)\n') do + + local devnum = util.read_file(devnum_path, nil, '*n') + local idata, odata = _STRING_MATCH(data_glob, devnum..':'..bus_num..':(%d+):(%d+)') + + if idata and odata then + idata_sum = idata_sum + _TONUMBER(idata) + odata_sum = odata_sum + _TONUMBER(odata) + + local io_sum = idata + odata + local io_sum_unit = util.get_unit(io_sum) + + USBTOP_LIST[#USBTOP_LIST + 1] = { + name = name, + device = util.read_file(_STRING_GSUB(devnum_path, 'devnum$', 'product'), '(.-)\n'), + io_sum_numeric = io_sum, + io_sum = util.precision_convert_bytes(io_sum, 'B', io_sum_unit, 3)..' '..io_sum_unit..'/s', + path = devnum_path + } + end + end + + local iunit = util.get_unit(idata_sum) + local ounit = util.get_unit(odata_sum) + + Text.set(port.idata.speed, cr, util.precision_convert_bytes(idata_sum, 'B', iunit, 3)..' '..iunit..'/s') + Text.set(port.odata.speed, cr, util.precision_convert_bytes(odata_sum, 'B', ounit, 3)..' '..ounit..'/s') + + ScalePlot.update(port.idata.plot, cr, idata_sum) + ScalePlot.update(port.odata.plot, cr, odata_sum) +end + +local __populate_inactive_port = function(port, cr, msg) + Text.set(port.link_speed, cr, msg) + Text.set(port.idata.speed, cr, '--') + Text.set(port.odata.speed, cr, '--') + ScalePlot.update(port.idata.plot, cr, 0) + ScalePlot.update(port.odata.plot, cr, 0) +end + +local __get_power_status = function(pci_path) + if util.read_file(util.execute_cmd('find '..pci_path.. + 'usb[1-4]/power/runtime_status -print -quit 2> /dev/null', '(.-)\n')) == 'active\n' then + return 'Disconnected' + else + return 'Suspended' + end +end + +local __update = function(cr) + _OS_EXECUTE("killall -q usbdump") + + for i = 1, #USBTOP_LIST do USBTOP_LIST[i] = nil end + + local data_glob = util.read_file(USB_IO_PATH) + + if _IO_OPEN('/sys/module/usbmon/') then + _OS_EXECUTE(USBDUMP_CMD) + if _IO_OPEN('/sys/module/xhci_pci/') then + --right ports + local port_1_bus, port_2_bus + + local right_glob = util.execute_cmd(FIND_RIGHT_PORTS) + + for path in _STRING_GMATCH(right_glob, '(.-)\n') do + local bus_num, port_num = _STRING_MATCH(path, '.-(%d)-(%d)') + + if port_num == '1' then + port_1_bus = bus_num + __populate_active_port(usb[1], cr, data_glob, bus_num, path, 'Port 1') + elseif port_num == '2' then + port_2_bus = bus_num + __populate_active_port(usb[2], cr, data_glob, bus_num, path, 'Port 2') + end + end + + if not (port_1_bus and port_2_bus) then + local power_status = __get_power_status(RIGHT_USB_PCI) + + if not port_1_bus then __populate_inactive_port(usb[1], cr, power_status) end + if not port_2_bus then __populate_inactive_port(usb[2], cr, power_status) end + end + else + __populate_inactive_port(usb[1], cr, STATUS_PCI_UNLOADED) + __populate_inactive_port(usb[2], cr, STATUS_PCI_UNLOADED) + end + + if _IO_OPEN('/sys/module/ehci_pci/') then + --left port + local left_path = util.execute_cmd(FIND_PORT_3, '(.-)\n') + + local left_hub_power_status + + if left_path == '' then + left_hub_power_status = __get_power_status(LEFT_USB_PCI) + __populate_inactive_port(usb[3], cr, left_hub_power_status) + else + __populate_active_port(usb[3], cr, data_glob, + _STRING_MATCH(left_path, 'usb(%d)'), left_path, 'Port 3') + end + + --sd port + local sd_path = util.execute_cmd(FIND_SD_SLOT, '(.-)\n') + + if sd_path == '' then + __populate_inactive_port(card_slot.port, cr, left_hub_power_status or + __get_power_status(LEFT_USB_PCI)) + else + __populate_active_port(card_slot.port, cr, data_glob, + _STRING_MATCH(sd_path, 'usb(%d)'), sd_path, 'SD Slot') + end + else + __populate_inactive_port(usb[3], cr, STATUS_PCI_UNLOADED) + __populate_inactive_port(card_slot.port, cr, STATUS_PCI_UNLOADED) + end + else + __populate_inactive_port(usb[1], cr, STATUS_USBMON_UNLOADED) + __populate_inactive_port(usb[2], cr, STATUS_USBMON_UNLOADED) + __populate_inactive_port(usb[3], cr, STATUS_USBMON_UNLOADED) + __populate_inactive_port(card_slot.port, cr, STATUS_USBMON_UNLOADED) + end + + local list_len = #USBTOP_LIST + + --sort usbtop_list (selection sort) + if list_len > 1 then + for i = 1, list_len do + local iMax = i + for j = i + 1, list_len do + if USBTOP_LIST[j].io_sum_numeric > USBTOP_LIST[iMax].io_sum_numeric then + iMax = j + end + end + if iMax ~= i then + local tmp = USBTOP_LIST[i] + USBTOP_LIST[i] = USBTOP_LIST[iMax] + USBTOP_LIST[iMax] = tmp + end + end + end + + local columns = usbtop.columns + + for i = 1, N_ROWS do + local current_entry = USBTOP_LIST[i] + + if current_entry then + TextColumn.set(columns[1].column, cr, i, current_entry.name) + TextColumn.set(columns[2].column, cr, i, current_entry.device) + TextColumn.set(columns[3].column, cr, i, current_entry.io_sum) + else + TextColumn.set(columns[1].column, cr, i, '--') + TextColumn.set(columns[2].column, cr, i, '--') + TextColumn.set(columns[3].column, cr, i, '--') + end + end +end + +_OS_EXECUTE(USBDUMP_CMD) + +local draw = function(cr, interface, trigger) + __update(cr) + + if interface == 1 then + Text.draw(usb.header.text, cr) + Line.draw(usb.header.underline, cr) + + __draw_device(usb[1], cr) + __draw_device(usb[2], cr) + __draw_device(usb[3], cr) + + Text.draw(card_slot.header.text, cr) + Line.draw(card_slot.header.underline, cr) + + __draw_device(card_slot.port, cr) + + Text.draw(usbtop.header.text, cr) + Line.draw(usbtop.header.underline, cr) + + local columns = usbtop.columns + local separators = usbtop.separators + + for i = 1, N_COLUMNS do + local column = columns[i] + Text.draw(column.header, cr) + TextColumn.draw(column.column, cr) + end + + for i = 1, N_COLUMNS - 1 do + Line.draw(separators[i], cr) + end + end +end + +return draw diff --git a/module/Weather.lua b/module/Weather.lua new file mode 100644 index 0000000..3ee7189 --- /dev/null +++ b/module/Weather.lua @@ -0,0 +1,470 @@ +local _CR = require 'CR' +local Widget = require 'Widget' +local Text = require 'Text' +local Line = require 'Line' +local TextColumn = require 'TextColumn' +local ScaledImage = require 'ScaledImage' +local util = require 'util' +local json = require 'json' +local schema = require 'default_patterns' + +local _STRING_MATCH = string.match +local _STRING_SUB = string.sub +local _STRING_UPPER = string.upper +local _OS_EXECUTE = os.execute + +local TIME_FORMAT = '%-I:%M %p' +local DATE_FORMAT = '%A' + +local SECTIONS = 6 +local WEATHER_UPDATE_INTERVAL = 900 + +local WEATHER_PATH = '/tmp/weather.json' +local ICON_PATH = CONSTRUCTION_GLOBAL.ABS_PATH .. '/images/weather/' +local RECENTLY_UPDATED_PATH = '/tmp/weather_recently_updated' +local NA = "N/A" +local NA_IMAGE_PATH = ICON_PATH .. 'na.png' + +--construction params +local SPACING = 20 +local HEADER_PAD = 20 +local ICON_PAD = 20 +local ICON_SIDE_LENGTH = 65 +local TEMP_SECTION_WIDTH = 140 +local SECTION_HEIGHT = HEADER_PAD + ICON_SIDE_LENGTH + 30 + +local __create_side_section = function(x_offset, y_offset, section_table) + for i = 1, SECTIONS do + section_table[i] = {} + local current_widget = section_table[i] + local current_y = y_offset + (i - 1) * SECTION_HEIGHT + + current_widget.desc = Widget.Text{ + x = x_offset, + y = current_y, + text_color = schema.blue, + } + + current_widget.period = Widget.Text{ + x = x_offset + CONSTRUCTION_GLOBAL.SIDE_WIDTH, + y = current_y, + x_align = 'right', + text_color = schema.blue + } + + current_widget.icon = Widget.ScaledImage{ + x = x_offset, + y = current_y + HEADER_PAD, + width = ICON_SIDE_LENGTH, + height = ICON_SIDE_LENGTH + } + + current_widget.temp1 = Widget.Text{ + x = x_offset + ICON_SIDE_LENGTH + 0.5 * TEMP_SECTION_WIDTH, + y = current_y + HEADER_PAD + 20, + x_align = 'center', + font_size = 28, + text_color = schema.blue + } + + current_widget.temp2 = Widget.Text{ + x = x_offset + ICON_SIDE_LENGTH + 0.5 * TEMP_SECTION_WIDTH, + y = current_y + HEADER_PAD + 50, + x_align = 'center', + font_size = 11 + } + + current_widget.label_column = Widget.TextColumn{ + x = x_offset + ICON_SIDE_LENGTH + TEMP_SECTION_WIDTH, + y = current_y + HEADER_PAD + 10, + spacing = SPACING, + 'H', + 'P', + 'W' + } + + current_widget.info_column = Widget.TextColumn{ + x = x_offset + CONSTRUCTION_GLOBAL.SIDE_WIDTH, + y = current_y + HEADER_PAD + 10, + spacing = SPACING, + x_align = 'right', + text_color = schema.blue, + num_rows = 3 + } + + if i < SECTIONS then + current_widget.divider = Widget.Line{ + p1 = { + x = x_offset, + y = current_y + SECTION_HEIGHT - 18 + }, + p2 = { + x = x_offset + CONSTRUCTION_GLOBAL.SIDE_WIDTH, + y = current_y + SECTION_HEIGHT - 18 + }, + line_pattern = schema.mid_grey + } + end + end +end + +--LEFT +local left = { + header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.LEFT_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "HOURLY FORECAST" + }, + hours = {} +} + +__create_side_section(CONSTRUCTION_GLOBAL.LEFT_X, left.header.bottom_y, left.hours) + +--CENTER +local center = {} + +center.header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.CENTER_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.CENTER_WIDTH, + header = "CURRENT CONDITIONS" +} + +center.current_desc = Widget.Text{ + x = CONSTRUCTION_GLOBAL.CENTER_X, + y = center.header.bottom_y, + text_color = schema.blue +} + +local CENTER_SPACING = SPACING + 5 +local INFO_Y = center.header.bottom_y + CENTER_SPACING + +center.icon = Widget.ScaledImage{ + x = CONSTRUCTION_GLOBAL.CENTER_X, + y = INFO_Y, + width = ICON_SIDE_LENGTH, + height = ICON_SIDE_LENGTH +} + +local TEXT_1_PAD = 80 +local TEXT_1_X = CONSTRUCTION_GLOBAL.CENTER_X + ICON_SIDE_LENGTH + TEXT_1_PAD + +center.current_temp = Widget.Text{ + x = TEXT_1_X, + y = INFO_Y + 11, + x_align = 'center', + font_size = 32, + text_color = schema.blue +} + +center.obs_time = Widget.Text{ + x = TEXT_1_X, + y = INFO_Y + 39, + x_align = 'center', + font_size = 11, +} + +center.place = Widget.Text{ + x = TEXT_1_X, + y = INFO_Y + 57, + x_align = 'center', + font_size = 11, +} + +local COLUMN_WIDTH = 189 +local LABEL_COLUMN_1_X = TEXT_1_X + TEXT_1_PAD + +center.label_column_1 = Widget.TextColumn{ + x = LABEL_COLUMN_1_X, + y = center.header.bottom_y, + spacing = CENTER_SPACING, + 'Feels Like', + 'Dewpoint', + 'Sky Coverage', + 'Humidity', + 'Precipitation' +} + +center.info_column_1 = Widget.TextColumn{ + x = LABEL_COLUMN_1_X + COLUMN_WIDTH, + y = center.header.bottom_y, + x_align = 'right', + text_color = schema.blue, + spacing = CENTER_SPACING, + num_rows = 5 +} + +local LABEL_COLUMN_2_X = LABEL_COLUMN_1_X + COLUMN_WIDTH + 20 + +center.label_column_2 = Widget.TextColumn{ + x = LABEL_COLUMN_2_X, + y = center.header.bottom_y, + spacing = CENTER_SPACING, + 'WindSpd', + 'WindDir', + 'Pressure', + 'Sunrise', + 'Sunset' +} + +center.info_column_2 = Widget.TextColumn{ + x = LABEL_COLUMN_2_X + COLUMN_WIDTH, + y = center.header.bottom_y, + x_align = 'right', + text_color = schema.blue, + spacing = CENTER_SPACING, + num_rows = 5 +} + +--RIGHT + +local right = { + header = Widget.Header{ + x = CONSTRUCTION_GLOBAL.RIGHT_X, + y = CONSTRUCTION_GLOBAL.TOP_Y, + width = CONSTRUCTION_GLOBAL.SIDE_WIDTH, + header = "6 DAY FORECAST" + }, + days = {} +} + +__create_side_section(CONSTRUCTION_GLOBAL.RIGHT_X, right.header.bottom_y, right.days) + +Widget = nil +schema = nil + +SPACING = nil +HEADER_BOTTOM_Y = nil +SECTION_HEIGHT = nil +INFO_Y = nil +TEXT_1_PAD = nil +TEXT_1_X = nil +COLUMN_WIDTH = nil +LABEL_COLUMN_1_X = nil +CENTER_SPACING = nil + +local __populate_section = function(current_section, cr, desc, period, icon_path, temp1, temp2, humidity, pop, wind) + if desc then + Text.set(current_section.desc, cr, Text.trim_to_length(desc, 20)) + else + Text.set(current_section.desc, cr, NA) + end + + Text.set(current_section.period, cr, period or NA) + + ScaledImage.set(current_section.icon, icon_path or NA_IMAGE_PATH) + + Text.set(current_section.temp1, cr, temp1 or NA) + Text.set(current_section.temp2, cr, temp2 or NA) + + TextColumn.set(current_section.info_column, cr, 1, humidity or NA) + TextColumn.set(current_section.info_column, cr, 2, pop or NA) + TextColumn.set(current_section.info_column, cr, 3, wind or NA) +end + +local __populate_center = function(center_section, cr, desc, icon_path, temp, obs_time, place, feels_like, + dewpoint, coverage, humidity, precip, wind, pressure, visibility, sunrise, sunset) + + if desc then + Text.set(center_section.current_desc, cr, Text.trim_to_length(desc, 20)) + else + Text.set(center_section.current_desc, cr, NA) + end + + ScaledImage.set(center_section.icon, icon_path or NA_IMAGE_PATH) + + Text.set(center_section.current_temp, cr, temp or NA) + Text.set(center_section.obs_time, cr, obs_time or NA) + Text.set(center_section.place, cr, place or NA) + + local info_column_1 = center_section.info_column_1 + + TextColumn.set(info_column_1, cr, 1, feels_like or NA) + TextColumn.set(info_column_1, cr, 2, dewpoint or NA) + TextColumn.set(info_column_1, cr, 3, coverage or NA) + TextColumn.set(info_column_1, cr, 4, humidity or NA) + TextColumn.set(info_column_1, cr, 5, precip or NA) + + local info_column_2 = center_section.info_column_2 + + TextColumn.set(info_column_2, cr, 1, wind or NA) + TextColumn.set(info_column_2, cr, 2, pressure or NA) + TextColumn.set(info_column_2, cr, 3, visibility or NA) + TextColumn.set(info_column_2, cr, 4, sunrise or NA) + TextColumn.set(info_column_2, cr, 5, sunset or NA) +end + +local __update_interface = function(cr) + local file = util.read_file(WEATHER_PATH) + local data = (file ~= '') and json.decode(file) + + if data then + data = data.response.responses + + if data[1].success == false then + for i = 1, SECTIONS do __populate_section(left.hours[i], cr) end + + __populate_center(center, cr, nil, nil, nil, nil, 'Invalid Location') + + for i = 1, SECTIONS do __populate_section(right.days[i], cr) end + else + --LEFT + local hourly = data[2].response[1].periods + + for i = 1, SECTIONS do + local hour_data = hourly[i] + + __populate_section( + left.hours[i], + cr, + hour_data.weatherPrimary, + hour_data.timestamp and util.convert_unix_time(hour_data.timestamp, TIME_FORMAT), + hour_data.icon and ICON_PATH..hour_data.icon, + hour_data.avgTempF and hour_data.avgTempF..'°F', + hour_data.feelslikeF and 'Feels like '..hour_data.feelslikeF..'°F', + hour_data.humidity and hour_data.humidity..' %', + hour_data.pop and hour_data.pop..' %', + hour_data.windSpeedMPH and hour_data.windSpeedMPH..' mph' + ) + end + + --CENTER + local current_data = data[1].response + local ob = current_data.ob + + local place + if current_data.place then + place = current_data.place.name + if place then place = util.capitalize_each_word(_STRING_MATCH(place, '([%w%s]+)/?')) end + + local state = current_data.place.state + if state == '' then state = nil end + + if place and state then + place = place..', '.._STRING_UPPER(state) + elseif place then + local country = current_data.place.country + if country then place = place..', '.._STRING_UPPER(country) end + end + end + + __populate_center( + center, + cr, + ob.weather, + ob.icon and ICON_PATH..ob.icon, + ob.tempF and ob.tempF..'°F', + ob.timestamp and util.convert_unix_time(ob.timestamp, TIME_FORMAT), + place, + ob.feelslikeF and ob.feelslikeF..'°F', + ob.dewpointF and ob.dewpointF..'°F', + ob.sky and ob.sky..' %', + ob.humidity and ob.humidity..' %', + ob.precipIN and ob.precipIN..' in', + ob.windSpeedMPH and ob.windSpeedMPH..' mph', + ob.windDirDEG and ob.windDirDEG..' deg', + ob.pressureMB and ob.pressureMB..' mbar', + ob.sunrise and util.convert_unix_time(ob.sunrise, TIME_FORMAT), + ob.sunset and util.convert_unix_time(ob.sunset, TIME_FORMAT) + ) + + --RIGHT + local daily = data[3].response[1].periods + + for i = 1, SECTIONS do + local day_data = daily[i] + + __populate_section( + right.days[i], + cr, + day_data.weatherPrimary, + day_data.timestamp and _STRING_SUB(util.convert_unix_time( + day_data.timestamp, DATE_FORMAT), 1, 3), + day_data.icon and ICON_PATH..day_data.icon, + day_data.maxTempF and day_data.maxTempF..'°F', + day_data.minTempF and 'Low of '..day_data.minTempF..'°F', + day_data.humidity and day_data.humidity..' %', + day_data.pop and day_data.pop..' %', + day_data.windSpeedMPH and day_data.windSpeedMPH..' mph' + ) + end + end + else + for i = 1, SECTIONS do __populate_section(left.hours[i], cr) end + + __populate_center(center, cr) + + for i = 1, SECTIONS do __populate_section(right.days[i], cr) end + end +end + +local __draw_sections = function(section_group, cr) + for i = 1, SECTIONS do + local section = section_group[i] + + if i < SECTIONS then Line.draw(section.divider, cr) end + + Text.draw(section.desc, cr) + Text.draw(section.period, cr) + ScaledImage.draw(section.icon) + Text.draw(section.temp1, cr) + Text.draw(section.temp2, cr) + TextColumn.draw(section.label_column, cr) + TextColumn.draw(section.info_column, cr) + end +end + +__update_interface(_CR) + +_CR = nil + +_OS_EXECUTE('get_weather.sh') + +local update_cycle = WEATHER_UPDATE_INTERVAL + +local draw = function(cr, interface, trigger) + if update_cycle == 0 then _OS_EXECUTE('get_weather.sh') end + + local recently_updated = util.read_file(RECENTLY_UPDATED_PATH, nil, '*n') + + if recently_updated == 1 then + update_cycle = WEATHER_UPDATE_INTERVAL + util.write_file(RECENTLY_UPDATED_PATH, 0) + end + + if recently_updated == 1 or trigger == 0 then __update_interface(cr) end + + update_cycle = update_cycle - 1 + + if interface == 1 then + --LEFT + Text.draw(left.header.text, cr) + Line.draw(left.header.underline, cr) + + __draw_sections(left.hours, cr) + + --CENTER + Text.draw(center.header.text, cr) + Line.draw(center.header.underline, cr) + + Text.draw(center.current_desc, cr) + ScaledImage.draw(center.icon) + Text.draw(center.current_temp, cr) + Text.draw(center.obs_time, cr) + Text.draw(center.place, cr) + + TextColumn.draw(center.label_column_1, cr) + TextColumn.draw(center.info_column_1, cr) + TextColumn.draw(center.label_column_2, cr) + TextColumn.draw(center.info_column_2, cr) + + --RIGHT + Text.draw(right.header.text, cr) + Line.draw(right.header.underline, cr) + + __draw_sections(right.days, cr) + end +end + +return draw diff --git a/schema/default_patterns.lua b/schema/default_patterns.lua new file mode 100644 index 0000000..49e2cd3 --- /dev/null +++ b/schema/default_patterns.lua @@ -0,0 +1,73 @@ +local c = {} + +local Color = require 'Color' + +local white = 0xffffffff + +local grey1 = 0xeeeeeeff +local grey2 = 0xbfbfbfff +local grey3 = 0xd6d6d6ff +local grey4 = 0x888888ff +local grey5 = 0x565656ff +local grey6 = 0x2f2f2fb2 +local black = 0x000000ff + +local blue1 = 0x99CEFFff +local blue2 = 0xBFE1FFff +local blue3 = 0x316BA6ff + +local red1 = 0xFF3333ff +local red2 = 0xFF8282ff +local red3 = 0xFFB8B8ff + +local purple1 = 0xeecfffff +local purple2 = 0xcb91ffff +local purple3 = 0x9523ffff + +c.white = Color.init{hex_rgba = white} + +c.light_grey = Color.init{hex_rgba = grey1} +c.mid_grey = Color.init{hex_rgba = grey3} +c.dark_grey = Color.init{hex_rgba = grey4} + +c.blue = Color.init{hex_rgba = blue2} +c.red = Color.init{hex_rgba = red2} +c.purple = Color.init{hex_rgba = purple2} + +c.grey_rounded = Color.Gradient{ + Color.ColorStop{hex_rgba = grey5, stop = 0.0}, + Color.ColorStop{hex_rgba = grey2, stop = 0.5}, + Color.ColorStop{hex_rgba = grey5, stop = 1.0} +} + +c.blue_rounded = Color.Gradient{ + Color.ColorStop{hex_rgba = blue3, stop = 0.0}, + Color.ColorStop{hex_rgba = blue1, stop = 0.5}, + Color.ColorStop{hex_rgba = blue3, stop = 1.0} +} + +c.red_rounded = Color.Gradient{ + Color.ColorStop{hex_rgba = red1, stop = 0.0}, + Color.ColorStop{hex_rgba = red3, stop = 0.5}, + Color.ColorStop{hex_rgba = red1, stop = 1.0} +} + +c.purple_rounded = Color.Gradient{ + Color.ColorStop{hex_rgba = purple3, stop = 0.0}, + Color.ColorStop{hex_rgba = purple1, stop = 0.5}, + Color.ColorStop{hex_rgba = purple3, stop = 1.0} +} + +--~ c.transparent_black = Color.Gradient{ + --~ Color.ColorStop{hex_rgba = grey6, stop = 0.0, force_alpha = 0.7}, + --~ Color.ColorStop{hex_rgba = black, stop = 1.0, force_alpha = 0.7} +--~ } + +c.transparent_black = Color.init{hex_rgba = black, force_alpha = 0.7} + +c.transparent_blue = Color.Gradient{ + Color.ColorStop{hex_rgba = blue3, stop = 0.0, force_alpha = 0.2}, + Color.ColorStop{hex_rgba = blue1, stop = 1.0, force_alpha = 1.0} +} + +return c diff --git a/scripts/get_weather.sh b/scripts/get_weather.sh new file mode 100755 index 0000000..78002ba --- /dev/null +++ b/scripts/get_weather.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +#read location +location_string=$(cat $CONKY_LUA_HOME/scripts/location) + +#get weather +weather_url="http://api.aerisapi.com/batch/" + +o_fields="fields=\ +place.name,\ +place.state,\ +place.country,\ +ob.timestamp,\ +ob.tempF,\ +ob.dewpointF,\ +ob.sky,\ +ob.humidity,\ +ob.pressureMB,\ +ob.windSpeedMPH,\ +ob.windDirDEG,\ +ob.weather,\ +ob.feelslikeF,\ +ob.icon,\ +ob.sunrise,\ +ob.sunset,\ +ob.precipIN" + +observations="/observations%3F$o_fields" + +h_fields="fields=\ +periods.timestamp,\ +periods.avgTempF,\ +periods.feelslikeF,\ +periods.pop,\ +periods.humidity,\ +periods.windSpeedMPH,\ +periods.icon,\ +periods.weatherPrimary" + +hourly="/forecasts%3Ffilter=4hr%26limit=6%26$h_fields" + +d_fields="fields=\ +periods.timestamp,\ +periods.minTempF,\ +periods.maxTempF,\ +periods.pop,\ +periods.humidity,\ +periods.windDir,\ +periods.icon,\ +periods.windSpeedMPH,\ +periods.weatherPrimary" + +daily="/forecasts%3Ffrom=tomorrow%26limit=6%26$d_fields" + +alerts="/alerts" + +id="client_id=TdJ5M1pUXWUUebhfRKSs2" +secret="client_secret=DmI2NHCO6BQ5hSH4yAECVJlgA8gYZ1C4BvNaGEuM" + +curl -s "$weather_url$location_string?requests=$observations,$hourly,$daily&$id&$secret" > /tmp/weather.json && \ +echo 1 > /tmp/weather_recently_updated & diff --git a/scripts/location b/scripts/location new file mode 100644 index 0000000..bd8ea97 --- /dev/null +++ b/scripts/location @@ -0,0 +1 @@ +30308 diff --git a/scripts/set_conky_interface.sh b/scripts/set_conky_interface.sh new file mode 100755 index 0000000..8f7ddf4 --- /dev/null +++ b/scripts/set_conky_interface.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "$1" > /tmp/conky_interface diff --git a/scripts/update_location.sh b/scripts/update_location.sh new file mode 100755 index 0000000..e8f513d --- /dev/null +++ b/scripts/update_location.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +location=$(zenity --text "Enter current location in one of the following formats + +lat,lon +city,state,[country] +city,country +zip +airport" --entry) + +location=${location//" "/"+"} +retval=$? +case $retval in + 0) + echo "$location" > $CONKY_LUA_HOME/scripts/location + get_weather.sh;; + 1) + echo "Cancel pressed.";; +esac