first commit

This commit is contained in:
Richard Ramsden 2011-07-31 21:51:22 -07:00
commit 943eb399c7
6 changed files with 171 additions and 0 deletions

5
README Normal file
View file

@ -0,0 +1,5 @@
(under-development) Pure Ruby implementation of the X Window System Protocol.
This library is based off of Mathieu Bouchard's work on his RubyX11 project.
The entire X Window Protocol is here located here for contributors :)
http://cvs.freedesktop.org/*checkout*/xorg/xc/doc/hardcopy/XProtocol/proto.PS.gz

14
lib/X11.rb Normal file
View file

@ -0,0 +1,14 @@
require 'rubygems'
require 'socket'
require 'active_support'
require 'hexdump'
require 'X11/protocol'
require 'X11/auth'
require 'X11/display'
module X11
# Return a format string, suitable for pack(), for a string padded to a multiple
# of 4 bytes. For instance, C<pack(padded('Hello'), 'Hello')> gives
# C<"Hello\0\0\0">.
def self.pad(x); x + "\0"*(-x.length & 3); end
end

72
lib/X11/auth.rb Normal file
View file

@ -0,0 +1,72 @@
# This module is an approximate ruby replacement for the libXau C library and the
# xauth(1) program. It reads and interprets the files (usually '~/.Xauthority') that
# hold authorization data used in connecting to X servers. Since it was written mainly
# for the use of X11::Protocol, its functionality is currently restricted to reading,
# not writing, of these files.
module X11
class Auth
FAILED = 0
AUTHENTICATE = 1
SUCCESS = 2
ADDRESS_TYPES = {
256 => :Local,
65535 => :Wild,
254 => :Netname,
253 => :Krb5Principal,
252 => :LocalHost,
0 => :Internet,
1 => :DECnet,
2 => :Chaos
}
AuthInfo = Struct.new :family, :address, :display, :auth_name, :auth_data
# Open an authority file, and create an object to handle it.
# The filename will be taken from the XAUTHORITY environment variable,
# if present, or '.Xauthority' in the user's home directory, or it may be overridden
# by an argument.
def initialize(path = ENV['XAUTHORITY'] || ENV['HOME'] + "/Xauthority")
@file = File.open(path)
end
# Get authentication data for a connection of type family to display display_id on host.
# If family is 'Internet', the host will be translated into an appropriate address by gethostbyname().
# If no data is found, returns nil
def get_by_hostname(host, family, display_id)
host = `hostname`.chomp if host == 'localhost' or host == '127.0.0.1'
address = TCPSocket.gethostbyname(host) if family == :Internet # this line does nothing for now
auth_data = nil
displays.each do |entry|
auth_data = entry if display_id.to_i == entry.display.to_i
end
reset
return auth_data
end
# returns one entry from Xauthority file
def read
auth_info = []
auth_info << ADDRESS_TYPES[ @file.read(2).unpack('n').first ]
4.times { length = @file.read(2).unpack('n').first; auth_info << @file.read(length).first }
AuthInfo[*auth_info]
end
# returns all entries from XAuthority file
def displays
collection = []
collection << read while !@file.eof?
reset
collection
end
def reset
@file.seek(0, IO::SEEK_SET)
end
end
end

62
lib/X11/display.rb Normal file
View file

@ -0,0 +1,62 @@
module X11
class Display
# Open a connection to the specified display (numbered from 0) on the specified host
def initialize(target = ENV['DISPLAY'])
target =~ /^([\w.-]*):(\d+)(?:.(\d+))?$/
host, display_id, screen_id = $1, $2, $3
family = nil
if host.empty?
@socket = UNIXSocket.new("/tmp/.X11-unix/X#{display_id}")
family = :Local
host = nil
else
@socket = TCPSocket.new(host,6000+display_id)
family = :Internet
end
authorize(host, family, display_id)
end
private
# authorization packet sent to X11 server:
# [:proto_major, Uint16],
# [:proto_minor, Uint16],
# [:auth_proto_name, Uint16, :length],
# [:auth_proto_data, Uint16, :length],
# [:auth_proto_name, String8],
# [:auth_proto_data, String8]
def authorize(host, family, display_id)
auth_info = Auth.new.get_by_hostname(host||"localhost", family, display_id)
auth_name, auth_data = auth_info.address, auth_info.auth_data
puts auth_name
puts auth_data
@socket.write([
Protocol::BYTE_ORDER,
Protocol::MAJOR,
Protocol::MINOR,
auth_name.length,
auth_data.length,
X11::pad(auth_name),
X11::pad(auth_data)
].pack("A2 SS SS xx") + X11::pad(auth_name) + X11::pad(auth_data))
case @socket.read(1).unpack("w").first
when X11::Auth::FAILED
len, major, minor, xlen = @socket.read(7).unpack("CSSS")
reason = @socket.read(xlen * 4)
reason = reason[0..len]
raise "Connection to server failed -- (version #{major}.#{minor}) #{reason}"
when X11::Auth::AUTHENTICATE
raise "Connection requires authentication"
when X11::Auth::SUCCESS
raise "fix me"
else
raise "received unknown opcode #{type}"
end
end
end
end

0
lib/X11/event.rb Normal file
View file

18
lib/X11/protocol.rb Normal file
View file

@ -0,0 +1,18 @@
module X11
class Protocol
# endiness of your machine
BYTE_ORDER = case [1].pack("L")
when "\0\0\0\1"
"B"
when "\1\0\0\0"
"l"
else
raise "Cannot determine byte order"
end
MAJOR = 11
MINOR = 0
end
end