#!/usr/bin/env ruby $PROGRAM_NAME = "moltenbar" # Base worker class class Worker def initialize(config, name, pipe) @config = config @name = name @pipe_in = pipe @my_config = config["mod"][name] end def run() @wpid = fork do $PROGRAM_NAME = "moltenbar: worker (#{@name})" Signal.trap("INT") do; end mainloop() end return @wpid end def mainloop() loop do self.write("I am a dummy") sleep(1) end end def get_pid() return @wpid end def kill() begin if Process.getpgid(@wpid) == Process.getpgid($$) puts "Killing pid: #{@wpid}" Process.kill("HUP", @wpid) end rescue Errno::ESRCH => err puts "#{err}: #{@wpid}" end end def write(data) @pipe_in.puts @name + "\0" + data end end class DoSystem < Worker def initialize(name, pipe) @name = name @pipe = pipe end def mainloop() @pipe.each do |cmd| system(cmd) end end end module Modules @modules = {} def self.add(name, class_name) @modules[name] = class_name end def self.get return @modules end end class Template def initialize(template) @template = template end def render(config, data) @config = config @panel_data = data return ERB.new(@template).result(binding()) end end # Kill the workers. def cleanup(workers) for w in workers do w.kill end exit(0) end def get_x_dims return `xrandr`.scan(/current (\d+) x (\d+)/).flatten end require 'erb' require 'yaml' require 'optparse' workers = [] panel_data = {} options = {} OptionParser.new do |opts| opts.banner = "Usage: moltenvar [-c]" opts.on("-cCONFIG_PATH", "--config=CONFIG_PATH", "Specify and alternative config location") do |v| options[:config_file] = v end end.parse! if ENV["XDG_CONFIG_HOME"] == nil conf_dir = ENV["HOME"] + "/.config/moltenbar" else conf_dir = ENV["XDG_CONFIG_HOME"] + "/moltenbar" end options[:config_file] ||= conf_dir + "/rc.yaml" config = YAML.load_file(options[:config_file]) config['mod_dir'] ||= conf_dir + "/mod" for m in config['modules'] do load("#{config['mod_dir']}/#{m}") end pipe_r, pipe_w = IO.pipe Modules.get.each do |k, v| m = Object.const_get(v).new(config, k, pipe_w) workers << m m.run end Signal.trap("INT") do cleanup(workers); end Signal.trap("TERM") do cleanup(workers); end if config['geometry'] == nil config['gap'] ||= 0 config['height'] ||= 14 gap = config['gap'].to_i if config['width'] == nil y, x = get_x_dims() config['width'] = y.to_i - (gap * 2) end config['geometry'] = "#{config['width']}x#{config['height']}+#{gap}+#{gap}" end lemonbar_cmd = [ "lemonbar", "-g", config['geometry'], "-f", config['fontspec'], "-n", config['window_name'], "-a", config['active_areas'], "-F", config['colours']['fg'], "-B", config['colours']['bg'] ] puts "Launching lemonbar as: " + lemonbar_cmd.join(" ") IO.popen(lemonbar_cmd, "w+") do |pipe_lb| pipe_lb.sync = true sys = DoSystem.new("system", pipe_lb) workers << sys sys.run() pipe_r.each do |line| mod_name, data = line.chomp.split("\0") panel_data[mod_name] = data t = Template.new(config['format']) pipe_lb.puts t.render(config, panel_data) end end