mirror of
https://github.com/vidarh/ruby-x11
synced 2024-11-16 07:48:12 +01:00
Handle the following requests:
CreateWindow, MapWindow, OpenFont, ListFonts, CreateGC, ChangeGC, ClearArea, PolyFillRectangle, ImageText8 Parse the following Events: Expose, MapNotify, ConfigureNotify Added example script
This commit is contained in:
parent
e13df2a2c4
commit
4e08564800
2 changed files with 317 additions and 7 deletions
85
example/test.rb
Normal file
85
example/test.rb
Normal file
|
@ -0,0 +1,85 @@
|
|||
require 'rubygems'
|
||||
require 'bundler'
|
||||
Bundler.setup(:default, :development)
|
||||
|
||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
||||
|
||||
require 'X11'
|
||||
|
||||
display = X11::Display.new
|
||||
screen = display.screens.first
|
||||
root = screen.root
|
||||
wid = display.new_id
|
||||
display.write_request(X11::Form::CreateWindow.new(
|
||||
screen.root_depth,
|
||||
wid,
|
||||
root,
|
||||
0, #x
|
||||
0, #y
|
||||
200,#w
|
||||
200,#h
|
||||
0,
|
||||
X11::Form::InputOutput,
|
||||
X11::Form::CopyFromParent,
|
||||
X11::Form::CWBackPixel | X11::Form::CWEventMask,
|
||||
[0xff8844, # RGB background
|
||||
X11::Form::SubstructureNotifyMask |
|
||||
# X11::Form::StructureNotifyMask | ## Move
|
||||
X11::Form::ExposureMask |
|
||||
X11::Form::KeyPressMask |
|
||||
X11::Form::ButtonPressMask
|
||||
]
|
||||
))
|
||||
puts "Mapping"
|
||||
display.write_request(X11::Form::MapWindow.new(wid))
|
||||
# Creating GC
|
||||
gc = display.new_id
|
||||
display.write_request(X11::Form::CreateGC.new(
|
||||
gc, screen.root,
|
||||
X11::Form::ForegroundMask,
|
||||
[0xff0000, # RGB foreground
|
||||
]
|
||||
))
|
||||
|
||||
$gc2 = display.new_id
|
||||
display.write_request(X11::Form::CreateGC.new(
|
||||
$gc2,
|
||||
screen.root,
|
||||
X11::Form::ForegroundMask|X11::Form::BackgroundMask,
|
||||
[0xffffff, # RGB foreground
|
||||
0x444444,
|
||||
]
|
||||
))
|
||||
|
||||
puts "Main loop"
|
||||
p gc
|
||||
|
||||
# This will wait for a reply
|
||||
p display.write_sync(X11::Form::ListFonts.new(10, "*7x13*"),
|
||||
X11::Form::ListFontsReply).names.map(&:to_s)
|
||||
|
||||
fid = display.new_id
|
||||
display.write_request(X11::Form::OpenFont.new(fid, "7x13"))
|
||||
display.write_request(X11::Form::ChangeGC.new($gc2, X11::Form::FontMask, [fid]))
|
||||
|
||||
|
||||
def redraw(display, wid, gc)
|
||||
p [:redraw, gc]
|
||||
display.write_request(X11::Form::PolyFillRectangle.new(
|
||||
wid, gc,
|
||||
[X11::Form::Rectangle.new(20,20, 60, 80)]
|
||||
))
|
||||
|
||||
display.write_request(X11::Form::ClearArea.new( false, wid, 30, 30, 5, 5))
|
||||
display.write_request(X11::Form::ImageText8.new(wid, $gc2, 30, 70, "Hello World"))
|
||||
end
|
||||
|
||||
loop do
|
||||
pkt = display.next_packet
|
||||
if pkt
|
||||
p pkt
|
||||
redraw(display, wid, gc)
|
||||
end
|
||||
end
|
||||
|
239
lib/X11/form.rb
239
lib/X11/form.rb
|
@ -27,8 +27,11 @@ module X11
|
|||
# initialize field accessors
|
||||
def initialize(*params)
|
||||
self.class.fields.each do |f|
|
||||
param = params.shift
|
||||
instance_variable_set("@#{f.name}", param)
|
||||
if !f.value
|
||||
param = params.shift
|
||||
#p [f,param]
|
||||
instance_variable_set("@#{f.name}", param)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -42,26 +45,42 @@ module X11
|
|||
value = s.type == :unused ? nil : instance_variable_get("@#{s.name}")
|
||||
case s.type
|
||||
when :field
|
||||
if s.value
|
||||
if s.value.respond_to?(:call)
|
||||
value = s.value.call(self)
|
||||
else
|
||||
value = s.value
|
||||
end
|
||||
end
|
||||
|
||||
if value.is_a?(BaseForm)
|
||||
value.to_packet
|
||||
else
|
||||
s.type_klass.pack(value)
|
||||
end
|
||||
when :unused
|
||||
"\x00" * s.size
|
||||
sz = s.size.respond_to?(:call) ? s.size.call(self) : s.size
|
||||
"\x00" * sz
|
||||
when :length
|
||||
s.type_klass.pack(value.size)
|
||||
when :string
|
||||
s.type_klass.pack(value)
|
||||
when :list
|
||||
value.collect do |obj|
|
||||
obj.to_packet
|
||||
p obj
|
||||
if obj.is_a?(BaseForm)
|
||||
obj.to_packet
|
||||
else
|
||||
s.type_klass.pack(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end.join
|
||||
end
|
||||
|
||||
class << self
|
||||
# FIXME: Doing small reads from socket is a bad idea, and
|
||||
# the protocol provides length fields that makes it unnecessary.
|
||||
def from_packet(socket)
|
||||
# fetch class level instance variable holding defined fields
|
||||
|
||||
|
@ -78,7 +97,8 @@ module X11
|
|||
end
|
||||
form.instance_variable_set("@#{s.name}", val)
|
||||
when :unused
|
||||
socket.read(s.size)
|
||||
sz = s.size.respond_to?(:call) ? s.size.call(self) : s.size
|
||||
socket.read(sz)
|
||||
when :length
|
||||
size = s.type_klass.unpack( socket.read(s.type_klass.size) )
|
||||
lengths[s.name] = size
|
||||
|
@ -96,14 +116,15 @@ module X11
|
|||
return form
|
||||
end
|
||||
|
||||
def field(*args)
|
||||
name, type_klass, type = args
|
||||
def field(name, type_klass, type = nil, value: nil)
|
||||
# name, type_klass, type = args
|
||||
class_eval { attr_accessor name }
|
||||
|
||||
s = OpenStruct.new
|
||||
s.name = name
|
||||
s.type = (type == nil ? :field : type)
|
||||
s.type_klass = type_klass
|
||||
s.value = value
|
||||
|
||||
@structs ||= []
|
||||
@structs << s
|
||||
|
@ -206,5 +227,209 @@ module X11
|
|||
field :formats, FormatInfo, :list
|
||||
field :screens, ScreenInfo, :list
|
||||
end
|
||||
|
||||
class Rectangle < BaseForm
|
||||
field :x, Int16
|
||||
field :y, Int16
|
||||
field :width, Uint16
|
||||
field :height, Uint16
|
||||
end
|
||||
|
||||
class Error < BaseForm
|
||||
field :error, Uint8
|
||||
field :code, Uint8
|
||||
field :sequence_number, Uint16
|
||||
field :bad_resource_id, Uint32
|
||||
field :minor_opcode, Uint16
|
||||
field :major_opcode, Uint8
|
||||
unused 21
|
||||
end
|
||||
|
||||
|
||||
# Requests
|
||||
|
||||
CopyFromParent = 0
|
||||
InputOutput = 1
|
||||
InputOnly = 2
|
||||
|
||||
CWBackPixel = 0x0002
|
||||
CWEventMask = 0x0800
|
||||
|
||||
KeyPressMask = 0x00001
|
||||
ButtonPressMask = 0x00004
|
||||
ExposureMask = 0x08000
|
||||
StructureNotifyMask = 0x20000
|
||||
SubstructureNotifyMask = 0x80000
|
||||
|
||||
class CreateWindow < BaseForm
|
||||
field :opcode, Uint8, value: 1
|
||||
field :depth, Uint8
|
||||
field :request_length, Uint16, value: ->(cw) { len = 8 + cw.value_list.length; p len; len }
|
||||
field :wid, Window
|
||||
field :parent, Window
|
||||
field :x, Int16
|
||||
field :y, Int16
|
||||
field :width, Uint16
|
||||
field :height, Uint16
|
||||
field :border_width, Uint16
|
||||
field :window_class, Uint16
|
||||
field :visual, VisualID
|
||||
field :value_mask, Bitmask
|
||||
field :value_list, Uint32, :list
|
||||
end
|
||||
|
||||
class MapWindow < BaseForm
|
||||
field :opcode, Uint8, value: 8
|
||||
unused 1
|
||||
field :request_length, Uint16, value: 2
|
||||
field :window, Window
|
||||
end
|
||||
|
||||
class OpenFont < BaseForm
|
||||
field :opcode, Uint8, value: 45
|
||||
unused 1
|
||||
field :request_length, Uint16, value: ->(of) {
|
||||
3+(of.name.length+3)/4
|
||||
}
|
||||
field :fid, Font
|
||||
field :name, Uint16, :length
|
||||
unused 2
|
||||
field :name, String8, :string
|
||||
end
|
||||
|
||||
class ListFonts < BaseForm
|
||||
field :opcode, Uint8, value: 49
|
||||
unused 1
|
||||
field :request_length, Uint16, value: ->(lf) {
|
||||
2+(lf.pattern.length+4)/4
|
||||
}
|
||||
field :max_names, Uint16
|
||||
field :length_of_pattern, Uint16,value: ->(lf) {
|
||||
lf.pattern.length
|
||||
}
|
||||
field :pattern, String8
|
||||
end
|
||||
|
||||
class Str < BaseForm
|
||||
field :name, Uint8, :length, value: ->(str) { str.name.length }
|
||||
field :name, String8Unpadded, :string
|
||||
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
end
|
||||
|
||||
class ListFontsReply < BaseForm
|
||||
field :reply, Uint8, value: 1
|
||||
unused 1
|
||||
field :sequence_number, Uint16
|
||||
field :reply_length, Uint32
|
||||
field :names, Uint16, :length
|
||||
unused 22
|
||||
field :names, Str, :list
|
||||
end
|
||||
|
||||
FunctionMask = 0x1
|
||||
PlaneMask = 0x2
|
||||
ForegroundMask = 0x04
|
||||
BackgroundMask = 0x08
|
||||
FontMask = 0x4000
|
||||
|
||||
class CreateGC < BaseForm
|
||||
field :opcode, Uint8, value: 55
|
||||
unused 1
|
||||
field :request_length, Uint16, value: ->(cw) {
|
||||
len = 4 + cw.value_list.length
|
||||
}
|
||||
field :cid, Gcontext
|
||||
field :drawable, Drawable
|
||||
field :value_mask, Bitmask
|
||||
field :value_list, Uint32, :list
|
||||
end
|
||||
|
||||
class ChangeGC < BaseForm
|
||||
field :opcode, Uint8, value: 56
|
||||
unused 1
|
||||
field :request_length, Uint16, value: ->(ch) {
|
||||
3+ ch.value_list.length
|
||||
}
|
||||
field :gc, Gcontext
|
||||
field :value_mask, Bitmask
|
||||
field :value_list, Uint32, :list
|
||||
end
|
||||
|
||||
class ClearArea < BaseForm
|
||||
field :opcode, Uint8, value: 61
|
||||
field :exposures, Bool
|
||||
field :request_length, Uint16, value: 4
|
||||
field :window, Window
|
||||
field :x, Int16
|
||||
field :y, Int16
|
||||
field :width, Uint16
|
||||
field :height, Uint16
|
||||
end
|
||||
|
||||
class PolyFillRectangle < BaseForm
|
||||
field :opcode, Uint8, value: 70
|
||||
unused 1
|
||||
field :request_length, Uint16, value: ->(ob) {
|
||||
len = 3 + 2*(Array(ob.rectangles).length)
|
||||
}
|
||||
field :drawable, Drawable
|
||||
field :gc, Uint32
|
||||
field :rectangles, Rectangle, :list
|
||||
end
|
||||
|
||||
class ImageText8 < BaseForm
|
||||
field :opcode, Uint8, value: 76
|
||||
field :n, Uint8, :length
|
||||
field :request_length, Uint16, value: ->(it) { 4+(it.n.length+4)/4 }
|
||||
field :drawable, Drawable
|
||||
field :gc, Gcontext
|
||||
field :x, Int16
|
||||
field :y, Int16
|
||||
field :n, String8, :string
|
||||
end
|
||||
|
||||
# Events (page ~157)
|
||||
# FIXME: Events have quite a bit of redundancy, but unfortunately
|
||||
# BaseForm can't handle subclassing well.
|
||||
|
||||
class Expose < BaseForm
|
||||
field :code, Uint8
|
||||
unused 1
|
||||
field :sequence_number, Uint16
|
||||
field :widow, Window
|
||||
field :x, Uint16
|
||||
field :y, Uint16
|
||||
field :width, Uint16
|
||||
field :height, Uint16
|
||||
field :count, Uint16
|
||||
unused 14
|
||||
end
|
||||
|
||||
class MapNotify < BaseForm
|
||||
field :code, Uint8
|
||||
unused 1
|
||||
field :sequence_number, Uint16
|
||||
field :event, Window
|
||||
field :override_redirect, Bool
|
||||
unused 19
|
||||
end
|
||||
|
||||
class ConfigureNotify < BaseForm
|
||||
field :code, Uint8
|
||||
unused 1
|
||||
field :sequence_number, Uint16
|
||||
field :event, Window
|
||||
field :above_sibling, Window
|
||||
field :x, Int16
|
||||
field :y, Int16
|
||||
field :width, Uint16
|
||||
field :height, Uint16
|
||||
field :border_width, Uint16
|
||||
field :override_redirect, Bool
|
||||
unused 5
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue