#!/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 if config["mod"][name] != nil @my_config = config["mod"][name] end 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 Panel attr_accessor :modData def initialize(config) @modData = {} @config = config end def render panel = @config["format"] @modData.each do |modName, modData| panel = panel.gsub(/@{#{modName}}/, modData) end @config["colours"].each do |colName, colValue| panel = panel.gsub(/C{#{colName}}/, colValue) end return panel 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 'yaml' require 'optparse' 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" Dir.new("#{config['mod_dir']}").each_child do |m| printf("Loading module: #{m}\n") load("#{config['mod_dir']}/#{m}") end config["panels"].each do |panelName, panelConf| pipe_r, pipe_w = IO.pipe panelConf["modules"].each do |modName, modType| modClass = Modules.get[modType] Object.const_get(modClass).new(panelConf, modName, pipe_w).run end Signal.trap("INT") do cleanup; end Signal.trap("TERM") do cleanup; end if panelConf['geometry'] == nil panelConf['gap'] ||= 0 panelConf['height'] ||= 14 gap = panelConf['gap'].to_i if panelConf['width'] == nil y, x = get_x_dims() panelConf['width'] = y.to_i - (gap * 2) end panelConf['geometry'] = "%{w}x%{h}+%{gap}+%{gap}" % [ w: panelConf['width'], h: panelConf['height'], gap: gap ] end lemonbar_cmd = [ "lemonbar", "-g", panelConf['geometry'], "-f", panelConf['fontspec'], "-n", panelConf['window_name'], "-a", panelConf['active_areas'], "-F", panelConf['colours']['fg'], "-B", panelConf['colours']['bg'] ] printf("Launching lemonbar as:\n %s\n", lemonbar_cmd.join(" ")) p = Panel.new(panelConf) 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") data ||= "" p.modData[mod_name] = data pipe_lb.printf("%s\n", p.render()) end end end