Skip to content

Instantly share code, notes, and snippets.

@dgfitch
Created September 1, 2009 14:42
Show Gist options
  • Save dgfitch/179126 to your computer and use it in GitHub Desktop.
Save dgfitch/179126 to your computer and use it in GitHub Desktop.
# Simple helper library from generic bindings
module Ratpoison
RATPOISON="ratpoison"
def self.method_missing m, *args, &block
command m.to_s, *args
end
def self.command(command, *args)
puts "Running '#{command}' with '#{args.join(' ')}'" if $DEBUG
return `#{RATPOISON} -c "#{command} #{args.join(' ')}"`
end
def self.commands(list)
operations = list.map { |a| '-c "' + a.gsub('"', '\\"') + '"' }
cmd = RATPOISON + " " + operations.join(" ")
return `#{cmd}`
end
def self.mode x=nil
if x
return Ratpoison.set("topkmap main").chomp
else
return Ratpoison.set("topkmap").chomp
end
end
def self.getenv(*args)
return Ratpoison.command("getenv", *args).chomp
end
def self.select_xid xid
if frame = physical_screens.frames.detect {|x| x.window == xid}
Ratpoison.sselect frame.screen
Ratpoison.fselect frame.number
end
end
def self.window_xid xid
windows_array.detect {|x| x.xid.to_s == xid.to_s }
end
def self.windows_array (*args)
a = command("windows %f %S %n %s %l %i %c %a %t")
return @cached_windows if @cached_windows_string and @cached_windows_string == a
@cached_windows_string = a
@cached_windows = a.map do |line|
if line[/^ /]
rest = line.gsub(/^ /, "").chomp
w = Window.new(nil, *rest.split(" ", 8))
else
rest = line.chomp
w = Window.new(*rest.split(" ", 9))
end
w.screen_session = parse_screen(w.title) if w.title and w.title[/^\>/]
w
end
@cached_windows
end
def self.current_window
windows_array.detect {|x| x.active}
end
def self.current_frame
current_physical_screen.frames.detect {|x| x.number == current_window.frame}
end
def self.current_screen
screens.detect {|x| x.active}
end
def self.physical_screens
PhysicalScreens.new
end
def self.current_physical_screen
physical_screens.detect {|x| x.active}
end
def self.frames screen
Frames.new screen
end
# This crap has lots of edge cases I don't care about in day to day use
# If I have windows with standing numbers in the title, things will get wacky
#
# (note to self: this is for screen(1) sessions, not ratpoison screens... confusing)
def self.parse_screen string
s = ScreenSession.new
(s.host, *rest) = string.split(/\s+/)
screen = Screen.new
rest.each do |x|
if x[/^[0-9]+\*?$/]
# Screen number, hopefully
screen = Screen.new
s << screen
screen.number = x[/[0-9]+/]
if x[/\*/]
screen.active = true
s.active_screen = screen
end
else
# Append to the current title
if screen.title
screen.title += " " + x
else
screen.title = x
end
end
end
return s
end
class ScreenSession < Array
attr_accessor :host, :active_screen
def number
active_screen.number
end
def self.select number
# TODO: Only jump if not already selected -- not sure how to efficiently do that though
if Ratpoison.current_window.screen_session
current_number = Ratpoison.current_window.screen_session.number
if number.to_i != current_number.to_i
Ratpoison.screen_key "'meta #{number}'"
end
end
end
end
# This represents a screen(1) screen, not a physical screen
class Screen
attr_accessor :number, :title, :active
def initialize
@active = false
end
end
class PhysicalScreens < Array
def initialize
Ratpoison.sdump.chomp.split(",").each do |x|
self << PhysicalScreen.new(*x.split(/ +/))
end
self
end
def frames
SFrames.new
end
end
class PhysicalScreen < Struct.new(:number, :x, :y, :width, :height, :status)
def active
status == "1"
end
def frames
Frames.new self.number
end
end
class Window < Struct.new(:frame, :screen, :number, :status, :last_access, :xid, :class, :name, :title, :screen_session)
def active
status == "*"
end
end
class Frames < Array
def initialize screen=nil
if screen
Ratpoison.fdump(screen).chomp.split(",")[0..-1].each do |f|
self << Frame.new(f)
end
end
self
end
def to_s
self.map {|x| x.to_s }.join(",") + ","
end
end
# SFrames is a collection of frames that have their screen numbers, used to
# do sfdump
class SFrames < Array
def initialize
Ratpoison.sfdump.chomp.split(",")[0..-1].each do |f|
d = f.sub(/\s+\d+$/, "")
frame = Frame.new(d)
frame.screen = f[/\d+$/]
self << frame
end
self
end
def to_s
sort_by {|x| x.number.to_i }.map {|x| x.to_s + " " + x.screen }.join(",") + ","
end
# Takes a frames array, the screen it originated from, and the screen it's
# going to, and fixes the settings
def move frames, from, to
new_frames = Ratpoison::Frames.new
frames.each do |f|
x = f.clone
x.screen = to.number
x.screenh = to.height
x.screenw = to.width
xd = from.width.to_f / to.width.to_f
yd = from.height.to_f / to.height.to_f
x.x = (x.x.to_f / xd).to_i
x.y = (x.y.to_f / yd).to_i
x.width = (x.width.to_f / xd).to_i
x.height = (x.height.to_f / yd).to_i
new_frames << x
end
return new_frames
end
end
class Frame < Struct.new(:screen, :number, :x, :y, :width, :height, :screenw, :screenh, :window, :last_access, :dedicated)
# This takes in ratpoison's sexp-style output - there's almost certainly a
# better way to do this
def initialize string=nil
if string
sexp = string.sub(/\)$/, "")
sexp.scan(/:([a-z\-]+) ([^ ]+)/) do |match|
name = $~[1].to_s
value = $~[2]
name = "last_access" if name == "last-access"
self[name] = value
end
end
end
def to_s
values = []
each_pair do |name, value|
case name.to_s
when "screen"
# Don't print out screen, the container array will decide whether or
# not to do so
when "last_access"
values << ":last-access " + value.to_s
else
values << ":" + name.to_s + " " + value.to_s
end
end
"(frame " + values.compact.join(" ") + ")"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment