ruby-x11/lib/X11/display.rb
Richard Ramsden a503b8391e add method to give unique ids for x11 resources
X11 Protocol expects clients to track unique identifiers in order to reduce 
network traffic. This reduces network traffic because when you create a new
resource say a window the X11 server doesn't have to reply with the ID
of the newly created resource. This makes the X11 protocol extremely fast
since most requests the server doesn't need to reply to a message.

In the first packet returned from X11 they give you a 
resource-id-mask and a resource-id-base. You can use these values to
generate a unique id for X11.
2012-05-19 15:47:50 -07:00

83 lines
2.4 KiB
Ruby

module X11
class DisplayError < X11Error; end
class ConnectionError < X11Error; end
class AuthorizationError < X11Error; end
class Display
attr_accessor :socket
# 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
def screens
@internal.screens.map do |s|
Screen.new(self, s)
end
end
##
# The resource-id-mask contains a single contiguous set of bits (at least 18).
# The client allocates resource IDs for types WINDOW, PIXMAP, CURSOR, FONT,
# GCONTEXT, and COLORMAP by choosing a value with only some subset of these
# bits set and ORing it with resource-id-base.
def new_id
id = (@xid_next ||= 0)
@xid_next += 1
(id & @internal.resource_id_mask) | @internal.resource_id_base
end
private
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
handshake = Packet::ClientHandshake.create(
Protocol::BYTE_ORDER,
Protocol::MAJOR,
Protocol::MINOR,
auth_name,
auth_data
)
@socket.write(handshake)
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 AuthorizationError, "Connection to server failed -- (version #{major}.#{minor}) #{reason}"
when X11::Auth::AUTHENTICATE
raise AuthorizationError, "Connection requires authentication"
when X11::Auth::SUCCESS
@socket.read(7) # skip unused bytes
@internal = Packet::DisplayInfo.read(@socket)
else
raise AuthorizationError, "Received unknown opcode #{type}"
end
end
def to_s
"#<X11::Display:0x#{object_id.to_s(16)} screens=#{@internal.screens.size}>"
end
end
end