Skip to content

Instantly share code, notes, and snippets.

@JeremyOttley
Created January 6, 2018 17:02
Show Gist options
  • Save JeremyOttley/f5539b1256a3063e26c33f429bf80e25 to your computer and use it in GitHub Desktop.
Save JeremyOttley/f5539b1256a3063e26c33f429bf80e25 to your computer and use it in GitHub Desktop.
jruby status bar
#!/usr/bin/env jruby
# coding: utf-8
# $Id: statusbar.rb,v 1.18 2016/10/07 22:27:26 jashank Exp $
require 'cgi'
require 'date'
require 'dbus'
require 'json'
require 'pg'
require 'pmap'
$colors = {
fg: "#ffffff",
bg: "#000000",
red: "#ff0000",
green: "#00ff00",
}
$sym = {
lock: "\u{f023}",
info_circle: "\u{f05a}",
unlock: "\u{f09c}",
rss: "\u{f09e}",
tachometer: "\u{f0e4}",
sitemap: "\u{f0e8}",
caret_square_o_down: "\u{f150}",
caret_square_o_up: "\u{f151}",
plug: "\u{f1e6}",
wifi: "\u{f1eb}",
battery_4: "\u{f240}",
battery_3: "\u{f241}",
battery_2: "\u{f242}",
battery_1: "\u{f243}",
battery_0: "\u{f244}",
pause_circle: "\u{f28b}",
bluetooth: "\u{f293}",
}
$sym.keys.each {|k| $sym[k] = '<span face="FontAwesome">' + $sym[k] + '</span>'}
@order = [
:taskmgr,
:ifwatch_bond0,
:ifwatch_enp0s25,
:wlwatch_wlp3s0,
:ifwatch_bnep0,
:ifwatch_tun0,
:battery,
:thermal,
:cpufreq,
:loadavg,
:date
]
# full_text: The full_text will be displayed by i3bar on the status
# line. This is the only required key.
#
# short_text: Where appropriate, the short_text (string) entry should
# also be provided.
#
# color: To make the current state of the information easy to spot,
# colors can be used. Colors are specified in hex (like in HTML),
# starting with a leading hash sign. For example, #ff0000 means red.
#
# background: Overrides the background color for this block.
#
# border: Overrides the border color for this block.
#
# min_width: The minimum width (in pixels) of the block; the value can
# also be a string, and the width of the text given determines the
# minimum width of the block.
#
# align: Align to the center, right or left (default) of the block.
#
# name and instance: Every block should have a unique name (string)
# entry so that it can be easily identified in scripts which process
# the output. i3bar completely ignores the name and instance
# fields. Make sure to also specify an instance (string) entry where
# appropriate. For example, the user can have multiple disk space
# blocks for multiple mount points.
#
# urgent: A boolean: whether the current value is urgent.
#
# separator: A boolean which specifies whether a separator line should
# be drawn after this block. The default is true, meaning the
# separator line will be drawn. Note that if you disable the separator
# line, there will still be a gap after the block, unless you also use
# separator_block_width.
#
# separator_block_width: The amount of pixels to leave blank after the
# block. In the middle of this gap, a separator line will be drawn
# unless separator is disabled. Normally, you want to set this to an
# odd value (the default is 9 pixels), since the separator line is
# drawn in the middle.
#
# markup: A string that indicates how the text of the block should be
# parsed. Set to "pango" to use Pango markup. Set to "none" to not use
# any markup (default).
$blocks = {
date: {
interval: 1,
proc: lambda {
s = DateTime.now.strftime("%Y-%m-%d %H:%M:%S");
{
name: "date",
full_text: s,
short_text: s[-8..-1],
color: $colors[:fg],
markup: "pango",
}
}
},
taskmgr: {
interval: 30,
proc: lambda {
res = $pg_tock.exec "select coalesce(current_task(), '[no current task]')"
{
name: "taskmgr",
full_text: res.getvalue(0, 0),
color: $colors[:fg],
markup: "pango",
}
}
},
ifwatch_bond0: {
interval: 5,
proc: lambda {
begin
ipl = `ip link show bond0 2>/dev/null`
status = !(ipl =~ /state UP/).nil?
ipa = ""
if status
ipa = `ip addr show bond0 2>/dev/null`
.split("\n")
.grep(/inet /)
.map {|i| i.strip }
if ipa.nil? or ipa.empty?
ipa = " (!v4)"
else
ipa = " " + ipa.first.split(' ')[1]
end
end
{
name: "ifwatch_bond0",
full_text: $sym[:sitemap] + ipa,
color: $colors[status ? :green : :red],
markup: "pango",
}
rescue
{
name: "ifwatch_bond0",
full_text: $sym[:sitemap],
color: $colors[:red],
markup: "pango",
}
end
}
},
ifwatch_enp0s25: {
interval: 5,
proc: lambda {
begin
ipl = `ip link show enp0s25 2>/dev/null`
status = !(ipl =~ /state UP/).nil?
{
name: "ifwatch_enp0s25",
full_text: $sym[status ? :caret_square_o_up : :caret_square_o_down],
color: $colors[status ? :green : :red],
markup: "pango",
}
rescue
{
name: "ifwatch_enp0s25",
full_text: $sym[:caret_square_o_down],
color: $colors[:red],
markup: "pango",
}
end
}
},
wlwatch_wlp3s0: {
interval: 5,
proc: lambda {
begin
iwi = `iwgetid -r wlp3s0`.chomp
status = (iwi != "")
iwi = CGI.escapeHTML iwi
{
name: "wlwatch_wlp3s0",
full_text: $sym[:wifi] + (status ? " #{iwi}" : ""),
color: $colors[status ? :green : :red],
markup: "pango",
}
rescue
{
name: "wlwatch_wlp3s0",
full_text: $sym[:wifi],
color: $colors[:red],
markup: "pango",
}
end
}
},
ifwatch_bnep0: {
interval: 5,
proc: lambda {
begin
ipl = `ip link show bnep0 2>/dev/null`
status = !(ipl =~ /state UP/).nil?
{
name: "ifwatch_bnep0",
full_text: $sym[:bluetooth],
color: $colors[status ? :green : :red],
markup: "pango",
}
rescue
{
name: "ifwatch_bnep0",
full_text: $sym[:bluetooth],
color: $colors[:red],
markup: "pango",
}
end
}
},
ifwatch_tun0: {
interval: 5,
proc: lambda {
begin
ipl = `ip link show tun0 2>/dev/null`
status = !(ipl =~ /,UP,/).nil?
{
name: "ifwatch_tun0",
full_text: $sym[status ? :lock : :unlock],
color: $colors[status ? :green : :red],
markup: "pango",
}
rescue
{
name: "ifwatch_tun0",
full_text: $sym[:unlock],
color: $colors[:red],
markup: "pango",
}
end
}
},
ifwatch_tap0: {
interval: 5,
proc: lambda {
begin
ipl = `ip link show tap0 2>/dev/null`
status = !(ipl =~ /,UP,/).nil?
{
name: "ifwatch_tap0",
full_text: $sym[status ? :lock : :unlock],
color: $colors[status ? :green : :red],
markup: "pango",
}
rescue
{
name: "ifwatch_tap0",
full_text: $sym[:unlock],
color: $colors[:red],
markup: "pango",
}
end
}
},
battery: {
interval: 30,
proc: lambda {
# https://upower.freedesktop.org/docs/Device.html#Device:State
acad = [1,4].include? $upower_ifa["State"]
pc = $upower_ifa["Energy"] / $upower_ifa["EnergyFull"]
etime = $upower_ifa["TimeToEmpty"]
ftime = $upower_ifa["TimeToFull"]
sym =
if acad then :plug
elsif 0.8 < pc and pc <= 1.0 then :battery_4
elsif 0.6 < pc and pc <= 0.8 then :battery_3
elsif 0.4 < pc and pc <= 0.6 then :battery_2
elsif 0.2 < pc and pc <= 0.4 then :battery_1
else :battery_0 end
col =
if acad then :fg
elsif sym == :battery_0 then :red
else :green end
timestr =
if acad
sprintf "%3d:%02d", (ftime/3660), (ftime%3600)/60
else
sprintf "%3d:%02d", (etime/3600), (etime%3600)/60
end
{
name: "battery",
full_text: sprintf(
"%s %.01f%% (%s)", $sym[sym], pc*100.0, timestr.strip),
color: $colors[col],
markup: "pango",
}
}
},
thermal: {
interval: 5,
proc: lambda {
therms = [0, 1].pmap {|i|
File.open ("/sys/devices/virtual/thermal/thermal_zone#{i}/temp") {|f|
f.to_a.first.chomp.to_f / 1000 } }
temp = therms.reduce(:+) / therms.length
fanstat = File.open ("/proc/acpi/ibm/fan") {|f|
f.to_a.map {|s| s.chomp } }
rpm = fanstat.grep(/^speed/).first.split("\t")[2].to_i
{
name: "thermal",
full_text: sprintf("%.01f°C (%d R)", temp, rpm),
color: $colors[temp >= 60.0 ? :red : :green],
markup: "pango",
}
}
},
cpufreq: {
interval: 2,
proc: lambda {
raw_freqs = (0..3).pmap {|i|
File.open ("/sys/devices/system/cpu/cpu#{i}/cpufreq/scaling_cur_freq") {|f|
f.to_a.first.chomp.to_i } }
raw_freq = raw_freqs.reduce(:+) / raw_freqs.length
freq_units =
if raw_freq >= 1e+6 then [ raw_freq.to_f / 1e+6, "G" ]
elsif raw_freq >= 1e+3 then [ raw_freq.to_f / 1e+3, "M" ]
else [ raw_freq, "k" ] end
freq, units = freq_units
str = (units != "G") ?
sprintf("#{$sym[:tachometer]} %d%s", freq, units) :
sprintf("#{$sym[:tachometer]} %.1f%s", freq, units)
{
name: "cpufreq",
full_text: str,
min_width: "#{$sym[:tachometer]} 888M",
align: "center",
color: $colors[raw_freq >= 2.6e+6 ? :red : :fg],
markup: "pango",
}
}
},
loadavg: {
interval: 5,
proc: lambda {
lavg = File.open ("/proc/loadavg") {|f|
f.to_a.first.chomp.split(' ')[0..2].map {|s| s.to_f} }
one, five, fifteen = lavg
{
name: "loadavg",
full_text: sprintf("%.02f:%.02f:%.02f", one, five, fifteen),
color: $colors[one >= 4 ? :red : :green],
markup: "pango",
}
}
},
}
$pg_tock = PG.connect dbname: "tock"
$dbus_sys = DBus.system_bus
$upower_svc = $dbus_sys["org.freedesktop.UPower"]
$upower_obj = $upower_svc.object "/org/freedesktop/UPower/devices/battery_BAT0"
$upower_obj.introspect
$upower_ifa = $upower_obj["org.freedesktop.UPower.Device"]
class Notifier < DBus::Object
@id = 0
dbus_interface "org.freedesktop.Notifications" do
dbus_method :GetCapabilities do
["body"]
end
dbus_method :Notify, "in app_name:s, in replaces_id:u, in app_icon:s, in summary:s, in body:s, in actions:av, in hints:{sv}, in action_timeout:i" do |app_name, replaces_id, app_icon, summary, body, actions, hints, action_timeout|
$notify_q << { app_name: app_name, summary: summary, body: body.strip, id: @id }
@id += 1
end
dbus_method :CloseNotification, "in id:u" do |id|
$stderr.puts "close #{id}"
end
dbus_method :GetServerInformation, "out name:s, out vendor:s, out version:s, out spec_version:s" do
["statusbar.rb", "Rulingia", "$Revision: 1.18 $", "1.2"]
end
end
end
$dbus_sess = DBus.session_bus
svc = nil
$notify_q = []
begin
svc = $dbus_sess.request_service "org.freedesktop.Notifications"
svc.export Notifier.new "/org/freedesktop/Notifications"
Thread.new {
dloop = DBus::Main.new
dloop << $dbus_sess
dloop.run
}
rescue DBus::NameRequestError => e
svc = nil
end
i = 0
puts "{\"version\":1}["
loop do
if $notify_q.empty?
# Normal behaviour
puts (
@order.pmap do |k|
$blocks[k][:val] =
$blocks[k][:proc].call if i % $blocks[k][:interval] == 0
$blocks[k][:val]
end.to_json + ","
)
else
# Empty the notification queue.
until $notify_q.empty?
curr = $notify_q.shift
out = [
{
name: "notification",
full_text: ($sym[:info_circle] + " " + curr[:app_name] + ": " + curr[:summary] +
($notify_q.length > 5 ? " (#{$notify_q.length})" : "#{curr[:body]}")),
short_text: ($sym[:info_circle] + " " + curr[:app_name] + ": " + curr[:summary] +
($notify_q.length > 5 ? " (#{$notify_q.length})" : "")),
markup: "pango",
}
]
puts out.to_json + ","
interval = ($notify_q.length > 5) ? 1 : 3
sleep interval
i += interval
end
end
sleep 1
i += 1
end
puts "]"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment