#!/usr/bin/env ruby $PROGRAM_NAME = "moltenbar" # Base worker class class Worker @@collector = [] class << self def instances return @@collector end end 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 @@collector << self return nil end def mainloop() loop do self.write("I am a dummy") sleep(1) end end def kill() begin if Process.getpgid(@wpid) == Process.getpgid($$) printf("Killing pid: %s\n", @wpid) Process.kill("HUP", @wpid) end rescue Errno::ESRCH => err printf("%s: %s\n", err, @wpid) end end def write(data) @pipe_in.printf("%s\0%s\n", @name, 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 Worker.instances.each do |w| 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' 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 opts.on("-h", "--help", "Show this message") do printf("%s", opts) exit(0) 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| Object.const_get(v).new(config, k, pipe_w).run end Signal.trap("INT") do cleanup; end Signal.trap("TERM") do cleanup; 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'] = "%{w}x%{h}+%{gap}+%{gap}" % [ w: config['width'], h: 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'] ] printf("Launching lemonbar as:\n %s\n", lemonbar_cmd.join(" ")) IO.popen(lemonbar_cmd, "w+") do |pipe_lb| pipe_lb.sync = true DoSystem.new("system", pipe_lb).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.printf("%s\n", t.render(config, panel_data)) end end