mirror of
https://github.com/vidarh/ruby-x11
synced 2024-12-27 09:59:21 +01:00
da2fe51596
More constants and requestsm including SendEvent, and a helper for ClientMessage, w/example
1221 lines
32 KiB
Ruby
1221 lines
32 KiB
Ruby
|
|
module X11
|
|
module Form
|
|
# A form object is an X11 packet definition. We use forms to encode
|
|
# and decode X11 packets as we send and receive them over a socket.
|
|
#
|
|
# We can create a packet definition as follows:
|
|
#
|
|
# class Point < BaseForm
|
|
# field :x, Int8
|
|
# field :y, Int8
|
|
# end
|
|
#
|
|
# p = Point.new(10,20)
|
|
# p.x => 10
|
|
# p.y => 20
|
|
# p.to_packet => "\n\x14"
|
|
#
|
|
# You can also read from a socket:
|
|
#
|
|
# Point.from_packet(socket) => #<Point @x=10 @y=20>
|
|
#
|
|
class Form
|
|
def self.structs
|
|
[]
|
|
end
|
|
|
|
def self.fields
|
|
[]
|
|
end
|
|
end
|
|
|
|
class BaseForm < Form
|
|
include X11::Type
|
|
|
|
# initialize field accessors
|
|
def initialize(*params)
|
|
self.class.fields.each do |f|
|
|
if !f.value
|
|
param = params.shift
|
|
#p [f,param]
|
|
instance_variable_set("@#{f.name}", param)
|
|
end
|
|
end
|
|
end
|
|
|
|
def to_packet(dpy)
|
|
# fetch class level instance variable holding defined fields
|
|
structs = self.class.structs
|
|
|
|
packet = structs.map do |s|
|
|
# fetch value of field set in initialization
|
|
|
|
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
|
|
#p [s,value]
|
|
|
|
if value.is_a?(BaseForm)
|
|
v = value.to_packet(dpy)
|
|
else
|
|
#p [s,value]
|
|
v = s.type_klass.pack(value, dpy)
|
|
end
|
|
#p v
|
|
v
|
|
when :unused
|
|
sz = s.size.respond_to?(:call) ? s.size.call(self) : s.size
|
|
"\x00" * sz
|
|
when :length, :format_length
|
|
#p [s,value]
|
|
#p [value.size]
|
|
s.type_klass.pack(value.size, dpy)
|
|
when :string
|
|
s.type_klass.pack(value, dpy)
|
|
when :list
|
|
Array(value).collect do |obj|
|
|
if obj.is_a?(BaseForm)
|
|
obj.to_packet(dpy)
|
|
else
|
|
s.type_klass.pack(obj, dpy)
|
|
end
|
|
end
|
|
end
|
|
end.join
|
|
end
|
|
|
|
class << self
|
|
def structs
|
|
superclass.structs + Array(@structs) #instance_variable_get("@structs"))
|
|
end
|
|
|
|
# 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
|
|
|
|
form = new
|
|
lengths = {}
|
|
|
|
structs.each do |s|
|
|
case s.type
|
|
when :field
|
|
val = if s.type_klass.superclass == BaseForm
|
|
s.type_klass.from_packet(socket)
|
|
else
|
|
s.type_klass.unpack( socket.read(s.type_klass.size) )
|
|
end
|
|
form.instance_variable_set("@#{s.name}", val)
|
|
when :unused
|
|
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
|
|
when :format_length
|
|
size = s.type_klass.unpack( socket.read(s.type_klass.size) )
|
|
lengths[s.name] = case form.format
|
|
when 8 then size
|
|
when 16 then size*2
|
|
when 32 then size*4
|
|
else 0
|
|
end
|
|
when :string
|
|
len = lengths[s.name]
|
|
val = s.type_klass.unpack(socket, len)
|
|
form.instance_variable_set("@#{s.name}", val)
|
|
when :list
|
|
len = lengths[s.name]
|
|
if len
|
|
val = len.times.collect do
|
|
s.type_klass.from_packet(socket)
|
|
end
|
|
else
|
|
val = []
|
|
while ob = s.type_klass.from_packet(socket)
|
|
val << ob
|
|
end
|
|
end
|
|
form.instance_variable_set("@#{s.name}", val)
|
|
end
|
|
end
|
|
|
|
return form
|
|
end
|
|
|
|
Field = Struct.new(:name, :type, :type_klass, :value, :size, keyword_init: true)
|
|
|
|
def field(name, type_klass, type = nil, value: nil)
|
|
# name, type_klass, type = args
|
|
class_eval do
|
|
if value && value.respond_to?(:call)
|
|
define_method(name.to_sym) { value.call(self) }
|
|
else
|
|
attr_accessor name
|
|
end
|
|
end
|
|
|
|
s = Field.new
|
|
s.name = name
|
|
s.type = (type == nil ? :field : type)
|
|
s.type_klass = type_klass
|
|
s.value = value
|
|
|
|
@structs ||= []
|
|
@structs << s
|
|
end
|
|
|
|
def unused(size)
|
|
@structs ||= []
|
|
@structs << Field.new(size: size, type: :unused)
|
|
end
|
|
|
|
def fields
|
|
super+Array(@structs).dup.delete_if{|s| s.type == :unused or s.type == :length or s.type == :format_length}
|
|
end
|
|
end
|
|
end
|
|
|
|
# # Predefined constants, that can be used in the form of symbols
|
|
|
|
module Atoms
|
|
PRIMARY = 1
|
|
SECONDARY = 2
|
|
ARC = 3
|
|
ATOM = 4
|
|
BITMAP = 5
|
|
CARDINAL = 6
|
|
COLORMAP = 7
|
|
CURSOR = 8
|
|
#...
|
|
STRING = 31
|
|
VISUALID = 32
|
|
WINDOW = 33
|
|
WM_COMMAND = 34
|
|
WM_HINTS = 35
|
|
end
|
|
|
|
PointerWindow = 0
|
|
InputFocus = 1
|
|
|
|
# FIXME: Deprecated in favour of the Constants module
|
|
AtomAtom=4
|
|
CardinalAtom=6
|
|
WindowAtom=33
|
|
|
|
##
|
|
## X11 Packet Defintions
|
|
##
|
|
|
|
class ClientHandshake < BaseForm
|
|
field :byte_order, Uint8
|
|
unused 1
|
|
field :protocol_major_version, Uint16
|
|
field :protocol_minor_version, Uint16
|
|
field :auth_proto_name, Uint16, :length
|
|
field :auth_proto_data, Uint16, :length
|
|
unused 2
|
|
field :auth_proto_name, String8, :string
|
|
field :auth_proto_data, String8, :string
|
|
end
|
|
|
|
class FormatInfo < BaseForm
|
|
field :depth, Uint8
|
|
field :bits_per_pixel, Uint8
|
|
field :scanline_pad, Uint8
|
|
unused 5
|
|
end
|
|
|
|
class VisualInfo < BaseForm
|
|
field :visual_id, VisualID
|
|
field :qlass, Uint8
|
|
field :bits_per_rgb_value, Uint8
|
|
field :colormap_entries, Uint16
|
|
field :red_mask, Uint32
|
|
field :green_mask, Uint32
|
|
field :blue_mask, Uint32
|
|
unused 4
|
|
end
|
|
|
|
class DepthInfo < BaseForm
|
|
field :depth, Uint8
|
|
unused 1
|
|
field :visuals, Uint16, :length
|
|
unused 4
|
|
field :visuals, VisualInfo, :list
|
|
end
|
|
|
|
class ScreenInfo < BaseForm
|
|
field :root, Window
|
|
field :default_colormap, Colormap
|
|
field :white_pixel, Colornum
|
|
field :black_pixel, Colornum
|
|
field :current_input_masks, Mask
|
|
field :width_in_pixels, Uint16
|
|
field :height_in_pixels, Uint16
|
|
field :width_in_millimeters, Uint16
|
|
field :height_in_millimeters, Uint16
|
|
field :min_installed_maps, Uint16
|
|
field :max_installed_maps, Uint16
|
|
field :root_visual, VisualID
|
|
field :backing_stores, Uint8
|
|
field :save_unders, Bool
|
|
field :root_depth, Uint8
|
|
field :depths, Uint8,:length
|
|
field :depths, DepthInfo, :list
|
|
end
|
|
|
|
class DisplayInfo < BaseForm
|
|
field :release_number, Uint32
|
|
field :resource_id_base, Uint32
|
|
field :resource_id_mask, Uint32
|
|
field :motion_buffer_size, Uint32
|
|
field :vendor, Uint16, :length
|
|
field :maximum_request_length, Uint16
|
|
field :screens, Uint8, :length
|
|
field :formats, Uint8, :length
|
|
field :image_byte_order, Signifigance
|
|
field :bitmap_bit_order, Signifigance
|
|
field :bitmap_format_scanline_unit, Uint8
|
|
field :bitmap_format_scanline_pad, Uint8
|
|
field :min_keycode, KeyCode
|
|
field :max_keycode, KeyCode
|
|
unused 4
|
|
field :vendor, String8, :string
|
|
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
|
|
|
|
# The original request
|
|
attr_accessor :request
|
|
end
|
|
|
|
# XRender structures
|
|
|
|
class DirectFormat < BaseForm
|
|
field :red, Uint16
|
|
field :red_mask, Uint16
|
|
field :green, Uint16
|
|
field :green_mask, Uint16
|
|
field :blue, Uint16
|
|
field :blue_mask, Uint16
|
|
field :alpha, Uint16
|
|
field :alpha_mask, Uint16
|
|
end
|
|
|
|
class PictVisual < BaseForm
|
|
field :visual, Uint32
|
|
field :format, Uint32
|
|
end
|
|
|
|
class PictDepth < BaseForm
|
|
field :depth, Uint8
|
|
unused 1
|
|
field :visuals, Uint16, :length
|
|
unused 4
|
|
field :visuals, PictVisual, :list
|
|
end
|
|
|
|
class PictScreen < BaseForm
|
|
field :depths, Uint32, :length
|
|
field :fallback, Uint32
|
|
field :depths, PictDepth, :list
|
|
end
|
|
|
|
class PictFormInfo < BaseForm
|
|
field :id, Uint32
|
|
field :type, Uint8
|
|
field :depth, Uint8
|
|
unused 2
|
|
field :direct, DirectFormat
|
|
field :colormap, Colormap
|
|
end
|
|
|
|
# # Requests
|
|
|
|
# Constants, p112 onwards
|
|
CopyFromParent = 0
|
|
InputOutput = 1
|
|
InputOnly = 2
|
|
|
|
CWBackPixmap = 0x0001
|
|
CWBackPixel = 0x0002
|
|
CWBorderPixmap= 0x0004
|
|
CWBorderPixel = 0x0008
|
|
CWBitGravity = 0x0010
|
|
CWWinGravity = 0x0020
|
|
CWBackingStore = 0x0040
|
|
CWBackingPlanes = 0x0080
|
|
CWBackingPixel = 0x0100
|
|
CWOverrideRedirect = 0x0200
|
|
CWSaveUnder = 0x0400
|
|
CWEventMask = 0x0800
|
|
CWColorMap = 0x2000
|
|
|
|
KeyPressMask = 0x000001
|
|
KeyReleaseMask = 0x000002
|
|
ButtonPressMask = 0x000004
|
|
ButtonReleaseMask = 0x000008
|
|
EnterWindowMask = 0x000010
|
|
LeaveWindowMask = 0x000020
|
|
PointerMotionMask = 0x000040
|
|
PointerMotionHintMask = 0x000080
|
|
Button1MotionMask = 0x000100
|
|
# 0x200 .. 0x40000; page 113
|
|
ExposureMask = 0x008000
|
|
VisibilityChangeMask = 0x010000
|
|
StructureNotifyMask = 0x020000
|
|
ResizeRedirectMask = 0x040000
|
|
SubstructureNotifyMask = 0x080000
|
|
SubstructureRedirectMask=0x100000
|
|
FocusChangeMask = 0x200000
|
|
PropertyChangeMask = 0x400000
|
|
ColormapChangeMask = 0x800000
|
|
OwnerGrabButtonMask = 0x100000
|
|
|
|
class CreateWindow < BaseForm
|
|
field :opcode, Uint8, value: 1
|
|
field :depth, Uint8
|
|
field :request_length, Uint16, value: ->(cw) { len = 8 + cw.value_list.length }
|
|
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 ChangeWindowAttributes < BaseForm
|
|
field :opcode, Uint8, value: 2
|
|
unused 1
|
|
field :request_length, Uint16, value: ->(cw) { 3 + cw.value_list.length }
|
|
field :window, Window
|
|
field :value_mask, Bitmask
|
|
field :value_list, Uint32, :list
|
|
end
|
|
|
|
class GetWindowAttributes < BaseForm
|
|
field :opcode, Uint8, value: 3
|
|
unused 1
|
|
field :request_length, Uint16, value: 2
|
|
field :window, Window
|
|
end
|
|
|
|
class WindowAttributes < BaseForm
|
|
field :reply, Uint8, value: 1
|
|
field :backing_store, Uint8
|
|
field :sequence_number, Uint16
|
|
field :reply_length, Uint32
|
|
field :visual, VisualID
|
|
field :wclass, Uint16
|
|
field :bit_gravity, Uint8
|
|
field :win_gravity, Uint8
|
|
field :backing_planes, Uint32
|
|
field :backing_pixel, Uint32
|
|
field :save_under, Bool
|
|
field :map_is_installed, Bool
|
|
field :map_state, Uint8
|
|
field :override_redirect, Bool
|
|
field :colormap, Colormap
|
|
field :all_event_masks, Uint32
|
|
field :your_event_masks, Uint32
|
|
field :do_not_propagate_mask, Uint16
|
|
unused 2
|
|
end
|
|
|
|
class DestroyWindow < BaseForm
|
|
field :opcode, Uint8, value: 4
|
|
unused 1
|
|
field :request_length, Uint16, value: 2
|
|
field :window, Window
|
|
end
|
|
|
|
class ChangeSaveSet < BaseForm
|
|
field :opcode, Uint8, value: 6
|
|
field :mode, Uint8
|
|
field :request_length, Uint16, value: 2
|
|
field :window, Window
|
|
end
|
|
|
|
class ReparentWindow < BaseForm
|
|
field :opcode, Uint8, value: 7
|
|
unused 1
|
|
field :request_length, Uint16, value: 4
|
|
field :window, Window
|
|
field :parent, Window
|
|
field :x, Int16
|
|
field :y, Int16
|
|
end
|
|
|
|
class MapWindow < BaseForm
|
|
field :opcode, Uint8, value: 8
|
|
unused 1
|
|
field :request_length, Uint16, value: 2
|
|
field :window, Window
|
|
end
|
|
|
|
class UnmapWindow < BaseForm
|
|
field :opcode, Uint8, value: 10
|
|
unused 1
|
|
field :request_length, Uint16, value: 2
|
|
field :window, Window
|
|
end
|
|
|
|
class ConfigureWindow < BaseForm
|
|
field :opcode, Uint8, value: 12
|
|
unused 1
|
|
field :request_length, Uint16, value: ->(cw) { 3 + cw.values.length }
|
|
field :window, Window
|
|
field :value_mask, Uint16
|
|
unused 2
|
|
field :values, Uint32, :list
|
|
end
|
|
|
|
class GetGeometry < BaseForm
|
|
field :opcode, Uint8, value: 14
|
|
unused 1
|
|
field :request_length, Uint16, value: 2
|
|
field :drawable, Drawable
|
|
end
|
|
|
|
class Geometry < BaseForm
|
|
field :reply, Uint8, value: 1
|
|
field :depth, Uint8
|
|
field :sequence_number, Uint16
|
|
field :reply_length, Uint32
|
|
field :root, Window
|
|
field :x, Int16
|
|
field :y, Int16
|
|
field :width, Uint16
|
|
field :height, Uint16
|
|
field :border_width, Uint16
|
|
unused 10
|
|
end
|
|
|
|
class QueryTree < BaseForm
|
|
field :opcode, Uint8, value: 15
|
|
unused 1
|
|
field :request_length, Uint16, value: 2
|
|
field :window, Window
|
|
end
|
|
|
|
class QueryTreeReply < BaseForm
|
|
field :reply, Uint8, value: 1
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :reply_length, Uint32
|
|
field :root, Window
|
|
field :parent, Window
|
|
field :children, Uint16, :length
|
|
unused 14
|
|
field :children, Window, :list
|
|
end
|
|
|
|
class InternAtom < BaseForm
|
|
field :opcode, Uint8, value: 16
|
|
field :only_if_exists, Bool
|
|
field :request_length, Uint16, value: ->(ia) {
|
|
2+(ia.name.length+3)/4
|
|
}
|
|
field :name, Uint16, value: ->(ia) {
|
|
ia.name.length
|
|
}
|
|
unused 2
|
|
field :name, String8, :string
|
|
end
|
|
|
|
class Reply < BaseForm
|
|
field :reply, Uint8
|
|
end
|
|
|
|
class InternAtomReply < Reply
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :reply_length, Uint32
|
|
field :atom, Atom
|
|
unused 20
|
|
end
|
|
|
|
class GetAtomName < BaseForm
|
|
field :opcode, Uint8, value: 17
|
|
unused 1
|
|
field :request_length, Uint16, value: 2
|
|
field :atom, Atom
|
|
end
|
|
|
|
class AtomName < Reply
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :reply_length, Uint32
|
|
field :name, Uint16, :length
|
|
unused 22
|
|
field :name, String8, :string
|
|
end
|
|
|
|
Replace = 0
|
|
Prepend = 1
|
|
Append = 2
|
|
|
|
class ChangeProperty < BaseForm
|
|
field :opcode, Uint8, value: 18
|
|
field :mode, Uint8
|
|
field :request_length, Uint16, value: ->(cp) {
|
|
#p [:data, cp.data, :len, cp.data.length, :total, 6+(cp.data.length+3)/4]
|
|
6+(cp.data.length+3)/4
|
|
}
|
|
field :window, Window
|
|
field :property, Atom
|
|
field :type, Atom
|
|
field :format, Uint8
|
|
unused 3
|
|
field :data, Uint32, value: ->(cp) { cp.data.length / (cp.format/8) }
|
|
field :data, Uint8, :list
|
|
end
|
|
|
|
class GetProperty < BaseForm
|
|
field :opcode, Uint8, value: 20
|
|
field :delete, Bool
|
|
field :request_length, Uint16, value: 6
|
|
field :window, Window
|
|
field :property, Atom
|
|
field :type, Atom
|
|
field :long_offset, Uint32
|
|
field :long_length, Uint32
|
|
end
|
|
|
|
class Property < BaseForm
|
|
field :reply, Uint8, value: 1
|
|
field :format, Uint8
|
|
field :sequence_number, Uint16
|
|
field :reply_length, Uint32
|
|
field :type, Atom
|
|
field :bytes_after, Uint32
|
|
field :value, Uint32, :format_length
|
|
unused 12
|
|
field :value, String8, :string
|
|
end
|
|
|
|
class SendEvent < BaseForm
|
|
field :opcode, Uint8, value: 25
|
|
field :propagate, Bool
|
|
field :request_length, Uint16, value: 11
|
|
field :destination, Window
|
|
field :event_mask, Uint32
|
|
field :event, Uint32 # FIXME: This is wrong, and will break on parsing.
|
|
end
|
|
|
|
class GrabButton < BaseForm
|
|
field :opcode, Uint8, value: 28
|
|
field :owner_events, Bool
|
|
field :request_length, Uint16, value: 6
|
|
field :grab_window, Window
|
|
field :event_mask, Uint16
|
|
field :pointer_mode, Uint8
|
|
field :keyboard_mode, Uint8
|
|
field :confine_to, Window
|
|
field :cursor, Cursor
|
|
field :button, Uint8
|
|
unused 1
|
|
field :modifiers, Uint16
|
|
end
|
|
|
|
class GrabKey < BaseForm
|
|
field :opcode, Uint8, value: 33
|
|
field :owner_event, Bool
|
|
field :request_length, Uint16, value: 4
|
|
field :grab_window, Window
|
|
field :modifiers, Uint16
|
|
field :keycode, Uint8
|
|
field :pointer_mode, Uint8
|
|
field :keyboard_mode, Uint8
|
|
unused 3
|
|
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 CreatePixmap < BaseForm
|
|
field :opcode, Uint8, value: 53
|
|
field :depth, Uint8
|
|
field :request_length, Uint16, value: 4
|
|
field :pid, Pixmap
|
|
field :drawable, Uint32
|
|
field :width, Uint16
|
|
field :height, Uint16
|
|
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
|
|
GraphicsExposures = 0x10000
|
|
|
|
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 CopyArea < BaseForm
|
|
field :opcode, Uint8, value: 62
|
|
unused 1
|
|
field :request_length, Uint16, value: 7
|
|
field :src_drawable, Drawable
|
|
field :dst_drawable, Drawable
|
|
field :gc, Gcontext
|
|
field :src_x, Uint16
|
|
field :src_y, Uint16
|
|
field :dst_x, Uint16
|
|
field :dst_y, Uint16
|
|
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
|
|
|
|
Bitmap = 0
|
|
XYPixmap=1
|
|
ZPixmap=2
|
|
|
|
class PutImage < BaseForm
|
|
field :opcode, Uint8, value: 72
|
|
field :format, Uint8
|
|
field :request_length, Uint16, value: ->(pi) {
|
|
6+(pi.data.length+3)/4
|
|
}
|
|
field :drawable, Drawable
|
|
field :gc, Gcontext
|
|
field :width, Uint16
|
|
field :height, Uint16
|
|
field :dstx, Int16
|
|
field :dsty, Int16
|
|
field :left_pad, Uint8
|
|
field :depth, Uint8
|
|
unused 2
|
|
field :data, String8 #, :string
|
|
end
|
|
|
|
class ImageText8 < BaseForm
|
|
field :opcode, Uint8, value: 76
|
|
field :n, Uint8, :length
|
|
field :request_length, Uint16, value: ->(it) { 4+(it.n.length+3)/4 }
|
|
field :drawable, Drawable
|
|
field :gc, Gcontext
|
|
field :x, Int16
|
|
field :y, Int16
|
|
field :n, String8, :string
|
|
end
|
|
|
|
class ImageText16 < BaseForm
|
|
field :opcode, Uint8, value: 77
|
|
field :n, Uint8, :length
|
|
field :request_length, Uint16, value: ->(it) { 4+(it.n.length*2+3)/4 }
|
|
field :drawable, Drawable
|
|
field :gc, Gcontext
|
|
field :x, Int16
|
|
field :y, Int16
|
|
field :n, String16, :string
|
|
end
|
|
|
|
class CreateColormap < BaseForm
|
|
field :opcode, Uint8, value: 78
|
|
field :alloc, Uint8
|
|
field :request_length, Uint16, value: 4
|
|
field :mid, Colormap
|
|
field :window, Window
|
|
field :visual, Uint32
|
|
end
|
|
|
|
class QueryExtension < BaseForm
|
|
field :opcode, Uint8, value: 98
|
|
unused 1
|
|
field :request_length, Uint16, value: ->(qe) { 2+(qe.name.length+3)/4 }
|
|
field :name, Uint16, :length
|
|
unused 2
|
|
field :name, String8
|
|
end
|
|
|
|
class QueryExtensionReply < Reply
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :reply_length, Uint32
|
|
field :present, Bool
|
|
field :major_opcode, Uint8
|
|
field :first_event, Uint8
|
|
field :first_error, Uint8
|
|
unused 20
|
|
end
|
|
|
|
class GetKeyboardMapping < BaseForm
|
|
field :opcode, Uint8, value: 101
|
|
unused 1
|
|
field :request_length, Uint16, value: 2
|
|
field :first_keycode, Uint8
|
|
field :count, Uint8
|
|
unused 2
|
|
end
|
|
|
|
class GetKeyboardMappingReply < Reply
|
|
field :keysyms_per_keycode, Uint8
|
|
field :sequence_number, Uint16
|
|
field :reply_length, Uint32
|
|
unused 24
|
|
field :keysyms, Keysym, :list
|
|
end
|
|
|
|
# Events (page ~157)
|
|
# FIXME: Events have quite a bit of redundancy, but unfortunately
|
|
# BaseForm can't handle subclassing well.
|
|
|
|
Shift = 0x001
|
|
Lock = 0x002
|
|
Control = 0x004
|
|
Mod1 = 0x008
|
|
Mod2 = 0x010
|
|
Mod3 = 0x0020
|
|
Mod4 = 0x0040
|
|
Mod5 = 0x0080
|
|
Button1 = 0x100
|
|
Button2 = 0x200
|
|
Button3 = 0x400
|
|
Button4 = 0x800
|
|
Button5 = 0x1000
|
|
|
|
class Event < BaseForm
|
|
field :code, Uint8
|
|
end
|
|
|
|
class SimpleEvent < Event
|
|
field :detail, Uint8
|
|
field :sequence_number, Uint16
|
|
end
|
|
|
|
class InputEvent < SimpleEvent
|
|
field :time, Uint32
|
|
field :root, Window
|
|
field :event, Window
|
|
field :child, Window
|
|
field :root_x, Int16
|
|
field :root_y, Int16
|
|
field :event_x, Int16
|
|
field :event_y, Int16
|
|
field :state, Uint16
|
|
end
|
|
|
|
class EnterLeaveNotify < InputEvent
|
|
field :mode, Uint8
|
|
field :same_screen_or_focus, Uint8
|
|
|
|
def same_screen = same_screen_or_focus.anybit?(0x02)
|
|
def focus = same_screen_or_focus.anybit?(0x01)
|
|
end
|
|
|
|
class EnterNotify < EnterLeaveNotify
|
|
end
|
|
|
|
class LeaveNotify < EnterLeaveNotify
|
|
end
|
|
|
|
class FocusIn < SimpleEvent
|
|
field :event, Window
|
|
field :mode, Uint8
|
|
unused 23
|
|
end
|
|
|
|
class FocusOut < FocusIn
|
|
end
|
|
|
|
class PressEvent < InputEvent
|
|
field :same_screen, Bool
|
|
unused 1
|
|
end
|
|
|
|
class ButtonPress < PressEvent
|
|
end
|
|
|
|
class KeyPress < PressEvent
|
|
end
|
|
|
|
class KeyRelease < PressEvent
|
|
end
|
|
|
|
class MotionNotify < PressEvent
|
|
end
|
|
|
|
class ButtonRelease < PressEvent
|
|
end
|
|
|
|
class ReparentNotify < SimpleEvent
|
|
field :event, Window
|
|
field :window, Window
|
|
field :parent, Window
|
|
field :x, Int16
|
|
field :y, Int16
|
|
field :override_redirect, Bool
|
|
unused 11
|
|
end
|
|
|
|
class ConfigureRequest < Event # 23
|
|
field :stack_mode, Uint8
|
|
field :sequence_number, Uint16
|
|
field :parent, Window
|
|
field :window, Window
|
|
field :sibling, Window
|
|
field :x, Int16
|
|
field :y, Int16
|
|
field :width, Uint16
|
|
field :height, Uint16
|
|
field :border_width, Uint16
|
|
field :value_mask, Uint16
|
|
unused 4
|
|
end
|
|
|
|
class Expose < SimpleEvent
|
|
field :window, Window
|
|
field :x, Uint16
|
|
field :y, Uint16
|
|
field :width, Uint16
|
|
field :height, Uint16
|
|
field :count, Uint16
|
|
unused 14
|
|
end
|
|
|
|
class NoExposure < SimpleEvent # 14
|
|
field :drawable, Drawable
|
|
field :minor_opcode, Uint16
|
|
field :major_opcode, Uint8
|
|
unused 21
|
|
end
|
|
|
|
class CreateNotify < SimpleEvent # 16
|
|
field :parent, Window
|
|
field :window, Window
|
|
field :x, Int16
|
|
field :y, Int16
|
|
field :width, Uint16
|
|
field :height, Uint16
|
|
field :border_width, Uint16
|
|
field :override_redirect, Bool
|
|
end
|
|
|
|
class DestroyNotify < Event
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :event, Window
|
|
field :window, Window
|
|
unused 20
|
|
end
|
|
|
|
class UnmapNotify < Event
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :event, Window
|
|
field :window, Window
|
|
field :from_configure, Bool
|
|
unused 19
|
|
end
|
|
|
|
class MapNotify < Event
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :event, Window
|
|
field :window, Window
|
|
field :override_redirect, Bool
|
|
unused 19
|
|
end
|
|
|
|
class MapRequest < Event
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :parent, Window
|
|
field :window, Window
|
|
unused 20
|
|
end
|
|
|
|
class ConfigureNotify < Event
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :event, Window
|
|
field :window, 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
|
|
|
|
class ClientMessage < Event
|
|
field :format, Uint8
|
|
field :sequence_number, Uint16
|
|
field :window, Window
|
|
field :type, Atom
|
|
field :data, X11::Type::Message
|
|
end
|
|
|
|
class PropertyNotify < Event # 28
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :window, Window
|
|
field :atom, Atom
|
|
field :time, Uint32
|
|
field :state, Uint8
|
|
unused 15
|
|
end
|
|
|
|
|
|
# XRender extension
|
|
# From https://cgit.freedesktop.org/xorg/proto/renderproto/tree/renderproto.h
|
|
class XRenderQueryVersion < BaseForm
|
|
field :req_type, Uint8
|
|
field :render_req_type, Uint8, value: 0
|
|
field :request_length, Uint16, value: 3
|
|
field :major_version, Uint32
|
|
field :minor_version, Uint32
|
|
end
|
|
|
|
class XRenderQueryVersionReply < Reply
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :request_length, Uint32
|
|
field :major_version, Uint32
|
|
field :minor_version, Uint32
|
|
#unused 16
|
|
end
|
|
|
|
class XRenderQueryPictFormats < BaseForm
|
|
field :req_type, Uint8
|
|
field :render_req_type, Uint8, value: 1
|
|
field :request_length, Uint16, value: 1
|
|
end
|
|
|
|
class XRenderQueryPictFormatsReply < Reply
|
|
unused 1
|
|
field :sequence_number, Uint16
|
|
field :length, Uint32
|
|
field :formats, Uint32, :length
|
|
field :screens, Uint32, :length
|
|
field :depths, Uint32, :length
|
|
field :visuals, Uint32, :length
|
|
field :subpixel, Uint32, :length
|
|
unused 4
|
|
field :formats, PictFormInfo, :list
|
|
field :screens, PictScreen, :list
|
|
field :subpixels, Uint32, :list
|
|
end
|
|
|
|
class XRenderCreatePicture < BaseForm
|
|
field :req_type, Uint8
|
|
field :render_req_type, Uint8, value: 4
|
|
field :request_length, Uint16, value: ->(cp) {
|
|
5 + Array(cp.value_list).length
|
|
}
|
|
field :pid, Uint32
|
|
field :drawable, Uint32
|
|
field :format, Uint32
|
|
field :value_mask, Uint32
|
|
field :value_list, Uint32, :list
|
|
end
|
|
|
|
class XRenderCreateGlyphSet < BaseForm
|
|
field :req_type, Uint8
|
|
field :render_req_type, Uint8, value: 17
|
|
field :request_length, Uint16, value: 3
|
|
field :gsid, Uint32
|
|
field :format, Uint32
|
|
end
|
|
|
|
class GlyphInfo < BaseForm
|
|
field :width, Uint16
|
|
field :height, Uint16
|
|
field :x, Int16
|
|
field :y, Int16
|
|
field :x_off, Int16
|
|
field :y_off, Int16
|
|
end
|
|
|
|
class XRenderAddGlyphs < BaseForm
|
|
field :req_type, Uint8
|
|
field :render_req_type, Uint8, value: 20
|
|
field :request_length, Uint16, value: ->(ag) {
|
|
if ag.glyphs.length != ag.glyphids.length
|
|
raise "Mismatch: Expected XRenderAddGlyphs glyphs and glyphids to be same length"
|
|
end
|
|
|
|
# GlyphInfo length == 3 + Glyphid length == 1
|
|
3 + ag.glyphs.length * 4 + (ag.data.length+3)/4
|
|
}
|
|
field :glyphset, Uint32
|
|
field :glyphs, Uint32, :length
|
|
field :glyphids, Uint32, :list
|
|
field :glyphs, GlyphInfo, :list
|
|
field :data, String8
|
|
end
|
|
|
|
class XRenderColor < BaseForm
|
|
field :red, Uint16
|
|
field :green, Uint16
|
|
field :blue, Uint16
|
|
field :alpha, Uint16
|
|
end
|
|
|
|
class GlyphElt32 < BaseForm
|
|
field :glyphs, Uint8, :length
|
|
unused 3
|
|
field :delta_x, Uint16
|
|
field :delta_y, Uint16
|
|
field :glyphs, Uint32, :list
|
|
end
|
|
|
|
# This is *also* the same as XRenderCOmpositeGlyphs16 and 8 w/other render_req_type,
|
|
# but do we care?
|
|
class XRenderCompositeGlyphs32 < BaseForm
|
|
field :req_type, Uint8
|
|
field :render_req_type, Uint8, value: 25
|
|
field :request_length, Uint16, value: ->(ch) {
|
|
7 + (ch.glyphcmds[0].glyphs.length + 2) # per glyphcmd
|
|
}
|
|
field :op, Uint8
|
|
unused 3
|
|
field :src, Uint32
|
|
field :dst, Uint32
|
|
field :mask_format, Uint32
|
|
field :glyphset, Uint32
|
|
field :xsrc, Uint16
|
|
field :ysrc, Uint16
|
|
# FIXME:
|
|
# We say this is a list, because technically it is
|
|
# But currently it'll break with more than one item.
|
|
field :glyphcmds, GlyphElt32, :list
|
|
end
|
|
|
|
class XRenderFillRectangles < BaseForm
|
|
field :req_type, Uint8
|
|
field :render_req_type, Uint8, value: 26
|
|
field :request_length, Uint16, value: ->(fr) { 5 + fr.rects.length * 2 }
|
|
field :op, Uint8
|
|
unused 3
|
|
field :dst, Uint32
|
|
field :color, Uint32
|
|
field :rects, Rectangle, :list
|
|
end
|
|
|
|
class XRenderCreateSolidFill < BaseForm
|
|
field :req_type, Uint8
|
|
field :render_req_type, Uint8, value: 33
|
|
field :request_length, Uint16, value: 4
|
|
field :fill, Uint32
|
|
field :color, XRenderColor
|
|
end
|
|
end
|
|
end
|