pure-x11 0.0.2 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3d89e6c8da43a6f489333c1d50f85485f1357bc0549747f11dbc2cf325e3af1
4
- data.tar.gz: 9b7ddd2b688c8c5d924a027a1d05b65744b52ad7f84a7e646c26ec610fb93d8e
3
+ metadata.gz: 0ecd289a7ec4a0a7f44bba1d05a437774ca6ed3d4c403b572b28a8691ef2a950
4
+ data.tar.gz: ac9460f0c0db0635e33358550176802119db88c9bb4dee097807f21c970f68ba
5
5
  SHA512:
6
- metadata.gz: ab203eb42daeda7e2091becae8de88582291ae8a7636035ed017f86e6195f928d2e7ff5945c356363ddba5ed63f7623158ac0004156cf76d5ff7e75092c32583
7
- data.tar.gz: 361fb690e60345acf764192386fc511a3ade0c724bb48f7f585fc573dcfe6c50386e7098e875d697a2be9406578c1c75ab7c57ddacda78dd8cc303067ee72bbc
6
+ metadata.gz: db23062260daabe75bfe5a9f419772be329023777c405ae7bb3a08125b9942f63ec8d635c1c11869648272d2c3ecad16a432fbca2d4d584d80ad2dbf15250d5a
7
+ data.tar.gz: f303d01e2c4b43fa2c5d44af4e469288684887c3efe71ee644275f233d584b9e342f9ebd80374632afe1199ad0d4182cebb515a95a7408b79aa36d239c9c9ffb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pure-x11 (0.0.2)
4
+ pure-x11 (0.0.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,8 +1,13 @@
1
- Ruby X11
1
+ Pure X11
2
2
  ========
3
3
 
4
+ This library is now on Rubygems.org as "pure-X11" as I (vidarh) has not had a
5
+ response from the original author. If that should change, I'll be happy to
6
+ upstread everything.
7
+
4
8
  (under-development) Pure Ruby implementation of the X Window System Protocol.
5
- This library is based off of Mathieu Bouchard's work on his RubyX11 project.
9
+ This library is based off of Mathieu Bouchard's work on his RubyX11 project,
10
+ and Richard Ramsdens excellent start on Ruby-X11.
6
11
 
7
12
  Contributors
8
13
  ------------
data/example/test.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'rubygems'
2
+ require 'skrift'
2
3
  require 'bundler'
3
4
  require 'chunky_png'
4
5
  Bundler.setup(:default, :development)
@@ -8,95 +9,164 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
9
 
9
10
  require 'X11'
10
11
 
11
- display = X11::Display.new
12
- screen = display.screens.first
12
+
13
+ dpy = display = X11::Display.new
14
+ screen = dpy.screens.first
13
15
  root = screen.root
14
- wid = display.new_id
15
- display.write_request(X11::Form::CreateWindow.new(
16
- screen.root_depth,
17
- wid,
18
- root,
19
- 0, #x
20
- 0, #y
21
- 1000,#w
22
- 600,#h
23
- 0,
24
- X11::Form::InputOutput,
25
- X11::Form::CopyFromParent,
26
- X11::Form::CWBackPixel |
27
- X11::Form::CWEventMask,
28
- [0xff8844, # RGB background
29
- X11::Form::SubstructureNotifyMask |
30
- # X11::Form::StructureNotifyMask | ## Move
31
- X11::Form::ExposureMask |
32
- X11::Form::KeyPressMask |
33
- X11::Form::ButtonPressMask
34
- ]
35
- ))
16
+
17
+ wid = dpy.create_window(
18
+ 0, 0, # x,y
19
+ 1000, 600, # w,h
20
+ # FIXME: WTH isn't depth: 32 working here?
21
+ depth: 24,
22
+ values: {
23
+ X11::Form::CWBackPixel => 0x0,
24
+ X11::Form::CWEventMask =>
25
+ (X11::Form::SubstructureNotifyMask |
26
+ X11::Form::StructureNotifyMask | ## Move
27
+ X11::Form::ExposureMask |
28
+ X11::Form::KeyPressMask |
29
+ X11::Form::ButtonPressMask)
30
+ }
31
+ )
32
+ #dpy.next_packet
33
+ #exit(0)
34
+
35
+ def set_window_opacity(dpy, wid, opacity)
36
+ dpy.change_property(
37
+ :replace,
38
+ wid, "_NET_WM_WINDOW_OPACITY",
39
+ :cardinal, 32,
40
+ [(0xffffffff * opacity).to_i].pack("V").unpack("C*")
41
+ )
42
+ end
43
+
44
+
45
+ set_window_opacity(dpy, wid, 0.8)
46
+
47
+ #p dpy.display_info
48
+
49
+ #reply = dpy.query_extension("XKEYBOARD")
50
+
51
+ $kmap = nil
52
+ def update_keymap(dpy)
53
+ reply = dpy.get_keyboard_mapping
54
+
55
+
56
+ if reply
57
+ $kmap = reply.keysyms.map do |c|
58
+ if c == 0
59
+ nil
60
+ elsif X11::KeySyms[c]
61
+ X11::KeySyms[c]
62
+ elsif c < 0x100
63
+ c.chr(Encoding::ISO_8859_1)
64
+ elsif c.between?(0xffb0, 0xffb9)
65
+ "KP_#{c-0xffb0}".to_sym
66
+ elsif c.between?(0xffbe, 0xffe0)
67
+ "F#{c-0xffbe+1}".to_sym
68
+ elsif c.between?(0xff08, 0xffff)
69
+ # FIIXME:
70
+ raise "keyboard_#{c.to_s(16)}".to_s
71
+ elsif c.between?(0x01000100, 0x0110FFFF)
72
+ (c-0x01000100).
73
+ chr(Encoding::UTF_32) rescue c.to_s(16)
74
+ else
75
+ raise "unknown_#{c.to_s(16)}"
76
+ end
77
+ end.each_slice(reply.keysyms_per_keycode).to_a
78
+ #ks = ks.map {|s| s.compact.sort_by{|x| x.to_s}.uniq }.to_a # This is for testing/ease of reading only
79
+ p $kmap[47-dpy.display_info.min_keycode]
80
+ end
81
+ end
82
+
83
+
84
+ def lookup_keysym(dpy, event)
85
+ update_keymap(dpy) if !$kmap
86
+ p $kmap[event.detail-dpy.display_info.min_keycode]
87
+ end
88
+
36
89
  puts "Mapping"
37
- display.write_request(X11::Form::MapWindow.new(wid))
38
- # Creating GC
39
- gc = display.new_id
40
- display.write_request(X11::Form::CreateGC.new(
41
- gc, screen.root,
42
- X11::Form::ForegroundMask,
43
- [0xff0000, # RGB foreground
44
- ]
45
- ))
46
-
47
- $gc2 = display.new_id
48
- display.write_request(X11::Form::CreateGC.new(
49
- $gc2,
50
- screen.root,
51
- X11::Form::ForegroundMask|X11::Form::BackgroundMask,
52
- [0xffffff, # RGB foreground
53
- 0x444444,
54
- ]
55
- ))
56
-
57
- $gc3 = display.new_id
58
- display.write_request(X11::Form::CreateGC.new(
59
- $gc3,
60
- screen.root,
61
- 0, []
62
- ))
90
+ dpy.map_window(wid)
91
+
92
+ $gc = gc = dpy.create_gc(wid, foreground: 0xff0000)
93
+ $gc2 = dpy.create_gc(wid,foreground: 0xffffff, background: 0x444444)
94
+ $gc3 = dpy.create_gc(wid)
63
95
 
64
96
 
65
97
  puts "Main loop"
66
- p gc
67
98
 
68
- # This will wait for a reply
69
- p display.write_sync(X11::Form::ListFonts.new(10, "*7x13*"),
70
- X11::Form::ListFontsReply).names.map(&:to_s)
99
+ #p dpy.list_fonts(10, "*7x13*").names.map(&:to_s)
71
100
 
72
- fid = display.new_id
73
- display.write_request(X11::Form::OpenFont.new(fid, "7x13"))
74
- display.write_request(X11::Form::ChangeGC.new($gc2, X11::Form::FontMask, [fid]))
101
+ fid = dpy.new_id
102
+ dpy.open_font(fid, "-misc-fixed-bold-r-normal--13-120-75-75-c-70-iso10646-1")
103
+ #"-bitstream-courier 10 pitch-medium-r-normal--0-0-0-0-m-0-iso10646-1")
104
+ dpy.change_gc($gc2, X11::Form::FontMask, [fid])
75
105
 
76
106
  $png = ChunkyPNG::Image.from_file('genie.png')
77
- p $png.width
78
- p $png.height
79
107
 
80
- def redraw(display, wid, gc)
81
- p [:redraw, gc]
82
- display.write_request(X11::Form::PolyFillRectangle.new(
83
- wid, gc,
84
- [X11::Form::Rectangle.new(20,20, 60, 80)]
85
- ))
108
+ $data = ""
109
+ $png.pixels.each do |px|
110
+ str = [px].pack("N")
111
+ if str[3] == "\x00"
112
+ $data << "\0\0\0\0".force_encoding("ASCII-8BIT")
113
+ else
114
+ $data << str[2] << str[1] << str[0] << str[3]
115
+ end
116
+ end
86
117
 
87
- display.write_request(X11::Form::ClearArea.new( false, wid, 30, 30, 5, 5))
88
- display.write_request(X11::Form::ImageText8.new(wid, $gc2, 30, 70, "Hello World"))
118
+ #$f = Font.load("/usr/share/fonts/truetype/tlwg/Umpush-BoldOblique.ttf")
119
+ $f = Font.load("/usr/share/fonts/truetype/tlwg/Garuda.ttf")
120
+ #$f = Font.load("resources/FiraGO-Regular.ttf")
89
121
 
122
+ $sft = SFT.new($f)
123
+ $sft.x_scale = 15
124
+ $sft.y_scale = 15
125
+ $glyphcache = {}
126
+ def render_glyph(display, wid, x,y, ch)
127
+ gid = $sft.lookup(ch.ord)
128
+ mtx = $sft.gmetrics(gid)
129
+ data = $glyphcache[gid]
130
+ if !data
131
+ img = Image.new(mtx.min_width, mtx.min_height) #(mtx .min_width + 3) & ~3, mtx.min_height)
132
+ if !$sft.render(gid, img)
133
+ raise "Unable to render #{gid}\n"
134
+ end
135
+ # p img
136
+ data = img.pixels.map {|px|
137
+ "\0\0"+px.chr+"\0" #+ "\0\0\0"
138
+ }.join.force_encoding("ASCII-8BIT")
139
+ $glyphcache[gid] = data
140
+ end
90
141
  depth = 24
91
- # FIXME: The colors are wrong
92
- # pixels.pack("N*")
93
- data = ""
94
- $png.pixels.each do |px|
95
- str = [px].pack("N")
96
- data << str[2] << str[1] << str[0] << str[3]
142
+ # p data
143
+ #p img
144
+ # p ch
145
+ display.put_image(
146
+ X11::Form::ZPixmap, wid, $gc2,
147
+ mtx.min_width,mtx.min_height,
148
+ x, y - mtx.y_offset, 0, depth, data
149
+ )
150
+ mtx.advance_width
151
+ end
152
+
153
+ def render_str(display, wid, x,y, str)
154
+ str.each_byte do |ch|
155
+ off = render_glyph(display, wid, x, y, ch.chr)
156
+ x+= off
97
157
  end
98
- display.write_request(X11::Form::PutImage.new(
99
- X11::Form::ZPixmap, wid, $gc2, $png.width, $png.height, 80, 80, 0, depth, data))
158
+ end
159
+
160
+ def redraw(dpy, wid, gc)
161
+ dpy.poly_fill_rectangle(wid, gc, [X11::Form::Rectangle.new(20,20, 60, 80)])
162
+ dpy.clear_area(false, wid, 30, 30, 5, 5)
163
+ dpy.image_text16(wid, $gc2, 30, 70, "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ")
164
+ #"\u25f0\u25ef Hello World")
165
+ dpy.put_image(
166
+ X11::Form::ZPixmap, wid, $gc2,
167
+ $png.width, $png.height, 80, 120, 0, 24, $data
168
+ )
169
+ render_str(dpy, wid, 30,90, 'HelloWorld')
100
170
  end
101
171
 
102
172
  loop do
@@ -104,5 +174,9 @@ loop do
104
174
  if pkt
105
175
  p pkt
106
176
  redraw(display, wid, gc) if pkt.is_a?(X11::Form::Expose)
177
+
178
+ if pkt.is_a?(X11::Form::KeyPress)
179
+ lookup_keysym(dpy,pkt)
180
+ end
107
181
  end
108
182
  end
data/lib/X11/display.rb CHANGED
@@ -26,7 +26,8 @@ module X11
26
26
  family = :Internet
27
27
  end
28
28
 
29
- authorize(host, family, display_id)
29
+ # FIXME
30
+ authorize(host, family, display_id) rescue nil
30
31
 
31
32
  @requestseq = 1
32
33
  @queue = []
@@ -67,6 +68,7 @@ module X11
67
68
  def read_error data
68
69
  error = Form::Error.from_packet(StringIO.new(data))
69
70
  STDERR.puts "ERROR: #{error.inspect}"
71
+ raise error.inspect
70
72
  error
71
73
  end
72
74
 
@@ -79,26 +81,47 @@ module X11
79
81
  end
80
82
 
81
83
  def read_event type, data, event_class
84
+ io = StringIO.new(data)
82
85
  case type
83
- when 2
84
- return Form::KeyPress.from_packet(StringIO.new(data))
85
- when 3
86
- return Form::KeyRelease.from_packet(StringIO.new(data))
87
- when 4
88
- return Form::ButtonPress.from_packet(StringIO.new(data))
89
- when 6
90
- return Form::MotionNotify.from_packet(StringIO.new(data))
91
- when 12
92
- return Form::Expose.from_packet(StringIO.new(data))
93
- when 14
94
- return Form::NoExposure.from_packet(StringIO.new(data))
95
- when 19
96
- return Form::MapNotify.from_packet(StringIO.new(data))
97
- when 22
98
- return Form::ConfigureNotify.from_packet(StringIO.new(data))
86
+ # 0 is error, not handled here
87
+ # 1 is reply, not handled here
88
+ when 2 then return Form::KeyPress.from_packet(io)
89
+ when 3 then return Form::KeyRelease.from_packet(io)
90
+ when 4 then return Form::ButtonPress.from_packet(io)
91
+ when 5 then return Form::ButtonRelease.from_packet(io)
92
+ when 6 then return Form::MotionNotify.from_packet(io)
93
+ when 7 then return Form::EnterNotify.from_packet(io)
94
+ when 8 then return Form::LeaveNotify.from_packet(io)
95
+ when 9 then return Form::FocusIn.from_packet(io)
96
+ when 10 then return Form::FocusOut.from_packet(io)
97
+ # FIXME 11: KeymapNotify
98
+ when 12 then return Form::Expose.from_packet(io)
99
+ # FIXME 13: GraphicsExposure
100
+ when 14 then return Form::NoExposure.from_packet(io)
101
+ # FIXME: 15: VisibilityNotify
102
+ when 16 then return Form::CreateNotify.from_packet(io)
103
+ when 17 then return Form::DestroyNotify.from_packet(io)
104
+ when 18 then return Form::UnmapNotify.from_packet(io)
105
+ when 19 then return Form::MapNotify.from_packet(io)
106
+ when 20 then return Form::MapRequest.from_packet(io)
107
+ when 21 then return Form::ReparentNotify.from_packet(io)
108
+ when 22 then return Form::ConfigureNotify.from_packet(io)
109
+ when 23 then return Form::ConfigureRequest.from_packet(io)
110
+ # FIXME: 24: GravityNotify
111
+ # FIXME: 25: ResizeRequest
112
+ # FIXME: 26: CirculateNotify
113
+ # FIXME: 27: CirculateRequest
114
+ when 28 then return Form::PropertyNotify.from_packet(io)
115
+ # FIXME: 29: SelectionClear
116
+ # FIXME: 30: SelectionRequest
117
+ # FIXME: 31: SelectionNotify
118
+ # FIXME: 32: ColormapNotify
119
+ when 33 then return Form::ClientMessage.from_packet(StringIO.new(data))
120
+ # FIXME: 34: MappingNotify
99
121
  else
100
122
  STDERR.puts "FIXME: Event: #{type}"
101
123
  STDERR.puts "EVENT: #{data.inspect}"
124
+ data
102
125
  end
103
126
  end
104
127
 
@@ -119,19 +142,28 @@ module X11
119
142
  data = read_full_packet(32)
120
143
  return nil if data.nil?
121
144
 
122
- type = data.unpack("C").first
145
+ # FIXME: What is bit 8 for? Synthentic?
146
+ type = data.unpack("C").first & 0x7f
123
147
  case type
124
- when 0
125
- read_error(data)
126
- when 1
127
- read_reply(data)
128
- when 2..34
129
- read_event(type, data, nil)
148
+ when 0 then read_error(data)
149
+ when 1 then read_reply(data)
150
+ when 2..34 then read_event(type, data, nil)
130
151
  else
131
- raise ProtocolError, "Unsupported reply type: #{type}"
152
+ raise ProtocolError, "Unsupported reply type: #{type} #{data.inspect}"
132
153
  end
133
154
  end
134
155
 
156
+ def write_raw_packet(pkt)
157
+ @requestseq += 1
158
+ @socket.write(pkt)
159
+ end
160
+
161
+ def write_packet(*args)
162
+ pkt = args.join
163
+ pkt[2..3] = u16(pkt.length/4)
164
+ write_raw_packet(pkt)
165
+ end
166
+
135
167
  def write_request ob
136
168
  #p data
137
169
  #p [:write_request, @requestseq, ob.class]
@@ -139,14 +171,16 @@ module X11
139
171
  #p [:AddGlyph,data] if ob.is_a?(X11::Form::XRenderAddGlyphs)
140
172
  #p [ob.request_length.to_i*4, data.size]
141
173
  raise "BAD LENGTH for #{ob.inspect} (#{ob.request_length.to_i*4} ! #{data.size} " if ob.request_length && ob.request_length.to_i*4 != data.size
142
- @requestseq += 1
143
- @socket.write(data)
174
+ write_raw_packet(data)
144
175
  end
145
176
 
146
177
  def write_sync(data, reply=nil)
178
+ seq = @requestseq
147
179
  write_request(data)
148
- pkt = next_reply
180
+ pkt = next_reply(seq)
149
181
  return nil if !pkt
182
+ return pkt if pkt.is_a?(X11::Form::Error)
183
+ pp reply
150
184
  reply ? reply.from_packet(StringIO.new(pkt)) : pkt
151
185
  end
152
186
 
@@ -158,17 +192,19 @@ module X11
158
192
  @queue.shift || read_packet
159
193
  end
160
194
 
161
- def next_reply
195
+ def next_reply(errseq)
162
196
  # FIXME: This is totally broken
163
197
  while pkt = read_packet
164
198
  if pkt.is_a?(String)
165
199
  return pkt
200
+ elsif pkt.is_a?(X11::Form::Error) && pkt.sequence_number == errseq
201
+ return pkt
166
202
  else
167
203
  @queue.push(pkt)
168
204
  end
169
205
  end
170
206
  end
171
-
207
+
172
208
  def run
173
209
  loop do
174
210
  pkt = read_packet
@@ -177,12 +213,54 @@ module X11
177
213
  end
178
214
  end
179
215
 
216
+ def find_visual(screen, depth, qlass = 4)
217
+ self.display_info.screens[screen].depths.find{|d|
218
+ d.depth == depth }.visuals.find{|v| v.qlass = qlass }
219
+ end
220
+
180
221
  # Requests
181
- def create_window(*args)
182
- write_request(X11::Form::CreateWindow.new(*args))
222
+ def create_window(x,y,w,h,
223
+ values: {},
224
+ depth: 32, parent: nil, border_width: 0, wclass: X11::Form::InputOutput, visual: nil
225
+ )
226
+ wid = new_id
227
+ parent ||= screens.first.root
228
+
229
+ if visual.nil?
230
+ visual = find_visual(0, depth).visual_id
231
+ end
232
+
233
+ values[X11::Form::CWColorMap] ||= create_colormap(0, parent, visual)
234
+
235
+ values = values.sort_by{_1[0]}
236
+ mask = values.inject(0) {|acc,v| (acc | v[0]) }
237
+ values = values.map{_1[1]}
238
+ write_request(
239
+ X11::Form::CreateWindow.new(
240
+ depth, wid, parent,
241
+ x,y,w,h,border_width, wclass, visual, mask, values)
242
+ )
243
+ return wid
244
+ end
245
+
246
+ def get_window_attributes(wid)
247
+ write_sync( Form::GetWindowAttributes.new(wid), Form::WindowAttributes )
248
+ end
249
+
250
+ def change_window_attributes(wid,
251
+ values: {})
252
+ values = values.sort_by{_1[0]}
253
+ mask = values.inject(0) {|acc,v| (acc | v[0]) }
254
+ values = values.map{_1[1]}
255
+ write_request(
256
+ X11::Form::ChangeWindowAttributes.new(wid, mask, values)
257
+ )
183
258
  end
184
259
 
260
+ def select_input(w, events) = change_window_attributes(w, values: {Form::CWEventMask => events})
261
+
185
262
  def atom(name)
263
+ name = name.to_sym
186
264
  intern_atom(false, name) if !@atoms[name]
187
265
  @atoms[name]
188
266
  end
@@ -211,6 +289,14 @@ module X11
211
289
  end
212
290
  end
213
291
 
292
+ def get_atom_name(atom)
293
+ reply = write_sync(X11::Form::GetAtomName.new(atom), X11::Form::AtomName)
294
+ reply&.name
295
+ end
296
+
297
+ def destroy_window(window) = write_request(X11::Form::DestroyWindow.new(window))
298
+ def get_geometry(drawable) = write_sync(X11::Form::GetGeometry.new(drawable), X11::Form::Geometry)
299
+
214
300
  def get_keyboard_mapping(min_keycode=display_info.min_keycode, count= display_info.max_keycode - min_keycode)
215
301
  write_sync(X11::Form::GetKeyboardMapping.new(min_keycode, count), X11::Form::GetKeyboardMappingReply)
216
302
  end
@@ -221,8 +307,35 @@ module X11
221
307
  mid
222
308
  end
223
309
 
224
- def change_property(*args)
225
- write_request(X11::Form::ChangeProperty.new(*args))
310
+ def get_property(window, property, type, offset: 0, length: 4, delete: false)
311
+ property = atom(property) if !property.is_a?(Integer)
312
+ type = atom_enum(type)
313
+
314
+ result = write_sync(X11::Form::GetProperty.new(
315
+ delete, window, property, type, offset, length
316
+ ), X11::Form::Property)
317
+
318
+ if result && result.format != 0
319
+ case result.format
320
+ when 16
321
+ result.value = result.value.unpack("v")
322
+ result.value = result.value.first if length == 2
323
+ when 32
324
+ result.value = result.value.unpack("V")
325
+ result.value = result.value.first if length == 4
326
+ end
327
+ elsif result
328
+ result.value = nil
329
+ end
330
+ result
331
+ end
332
+
333
+ def change_property(mode, window, property, type, format, data)
334
+ property = atom(property.to_sym) if property.is_a?(Symbol) || property.is_a?(String)
335
+
336
+ mode = open_enum(mode, {replace: 0, prepend: 1, append: 2})
337
+ type = atom_enum(type)
338
+ write_request(X11::Form::ChangeProperty.new(mode, window, property, type, format, data))
226
339
  end
227
340
 
228
341
  def list_fonts(*args)
@@ -230,16 +343,108 @@ module X11
230
343
  X11::Form::ListFontsReply)
231
344
  end
232
345
 
233
- def open_font(*args)
234
- write_request(X11::Form::OpenFont.new(*args))
346
+ def open_font(*args) = write_request(X11::Form::OpenFont.new(*args))
347
+ def change_gc(*args) = write_request(X11::Form::ChangeGC.new(*args))
348
+ def change_save_set(...)= write_request(X11::Form::ChangeSaveSet.new(...))
349
+ def reparent_window(window, parent, x, y, save: true)
350
+ # You so almost always want this that it should've been a single request
351
+ change_save_set(0, window) if save
352
+ write_request(X11::Form::ReparentWindow.new(window, parent, x,y))
353
+ end
354
+
355
+ def map_window(*args) = write_request(X11::Form::MapWindow.new(*args))
356
+ def unmap_window(*args) = write_request(X11::Form::UnmapWindow.new(*args))
357
+
358
+ def u8(*args) = args.pack("c*")
359
+ def u16(*args) = args.pack("v*")
360
+ def u32(*args) = args.pack("V*")
361
+ def atom_enum(val) = open_enum(val, {cardinal: Form::CardinalAtom, atom: Form::AtomAtom, window: Form::WindowAtom})
362
+ def window(*args)
363
+ args.each {|a| raise "Window expected" if a.nil? }
364
+ u32(*args)
365
+ end
366
+
367
+ def open_enum(val, map) = (map[val].nil? ? val : map[val])
368
+
369
+ def set_input_focus(revert_to, focus, time=:now)
370
+ # FIXME: This is an experiment.
371
+ # Upside: Simpler. Downside: Doesn't work server-side.
372
+ #
373
+ revert_to = open_enum(revert_to, {none: 0, pointer_root: 1, parent: 2})
374
+ focus = open_enum(focus, {none: 0, pointer_root: 1 })
375
+ time = open_enum(time, {current_time: 0, now: 0})
376
+ write_packet(u8(42,revert_to), u16(3), window(focus), u32(time))
377
+ end
378
+
379
+ def grab_key(owner_events, grab_window, modifiers, keycode, pointer_mode, keyboard_mode)
380
+ write_request(X11::Form::GrabKey.new(
381
+ owner_events,
382
+ grab_window,
383
+ modifiers,
384
+ keycode,
385
+ pointer_mode == :async ? 1 : 0,
386
+ keyboard_mode == :async ? 1 : 0
387
+ ))
235
388
  end
236
389
 
237
- def change_gc(*args)
238
- write_request(X11::Form::ChangeGC.new(*args))
390
+ def grab_button(owner_events, grab_window, event_mask, pointer_mode,
391
+ keyboard_mode, confine_to, cursor, button, modifiers)
392
+ write_request(X11::Form::GrabButton.new(
393
+ owner_events, grab_window, event_mask,
394
+ pointer_mode == :async ? 1 : 0,
395
+ keyboard_mode == :async ? 1 : 0,
396
+ confine_to.to_i, cursor.to_i, button, modifiers)
397
+ )
239
398
  end
240
399
 
241
- def map_window(*args)
242
- write_request(X11::Form::MapWindow.new(*args))
400
+ def configure_window(window, x: nil, y: nil, width: nil, height: nil,
401
+ border_width: nil, sibling: nil, stack_mode: nil)
402
+
403
+ mask = 0
404
+ values = []
405
+
406
+ if x
407
+ mask |= 0x001
408
+ values << x
409
+ end
410
+
411
+ if y
412
+ mask |= 0x002
413
+ values << y
414
+ end
415
+
416
+ if width
417
+ mask |= 0x004
418
+ values << width
419
+ end
420
+
421
+ if height
422
+ mask |= 0x008
423
+ values << height
424
+ end
425
+
426
+ if border_width
427
+ mask |= 0x010
428
+ values << border_width
429
+ end
430
+
431
+ if sibling
432
+ mask |= 0x020
433
+ values << sibling
434
+ end
435
+
436
+ if stack_mode
437
+ mask |= 0x040
438
+ values << case stack_mode
439
+ when :above then 0
440
+ when :below then 1
441
+ when :top_if then 2
442
+ when :bottom_if then 3
443
+ when :opposite then 4
444
+ else raise "Unknown stack_mode #{stack_mode.inspect}"
445
+ end
446
+ end
447
+ write_request(X11::Form::ConfigureWindow.new(window, mask, values))
243
448
  end
244
449
 
245
450
 
@@ -265,29 +470,12 @@ module X11
265
470
  gc
266
471
  end
267
472
 
268
- def put_image(*args)
269
- write_request(X11::Form::PutImage.new(*args))
270
- end
271
-
272
- def clear_area(*args)
273
- write_request(X11::Form::ClearArea.new(*args))
274
- end
275
-
276
- def copy_area(*args)
277
- write_request(X11::Form::CopyArea.new(*args))
278
- end
279
-
280
- def image_text8(*args)
281
- write_request(X11::Form::ImageText8.new(*args))
282
- end
283
-
284
- def image_text16(*args)
285
- write_request(X11::Form::ImageText16.new(*args))
286
- end
287
-
288
- def poly_fill_rectangle(*args)
289
- write_request(X11::Form::PolyFillRectangle.new(*args))
290
- end
473
+ def put_image(*args) = write_request(X11::Form::PutImage.new(*args))
474
+ def clear_area(*args) = write_request(X11::Form::ClearArea.new(*args))
475
+ def copy_area(*args) = write_request(X11::Form::CopyArea.new(*args))
476
+ def image_text8(*args) = write_request(X11::Form::ImageText8.new(*args))
477
+ def image_text16(*args)= write_request(X11::Form::ImageText16.new(*args))
478
+ def poly_fill_rectangle(*args) = write_request(X11::Form::PolyFillRectangle.new(*args))
291
479
 
292
480
  def create_pixmap(depth, drawable, w,h)
293
481
  pid = new_id
@@ -329,7 +517,7 @@ module X11
329
517
  s.depths.map do |d|
330
518
  d.visuals.map {|v| v.visual == visual ? v : nil }
331
519
  end
332
- end.flatten.compact.first.format
520
+ end.flatten.compact.first&.format
333
521
  end
334
522
 
335
523
  def render_find_standard_format(sym)
@@ -411,7 +599,12 @@ module X11
411
599
  auth = Auth.new
412
600
  auth_info = auth.get_by_hostname(host||"localhost", family, display_id)
413
601
 
414
- auth_name, auth_data = auth_info.auth_name, auth_info.auth_data
602
+ if auth_info
603
+ auth_name, auth_data = auth_info.auth_name, auth_info.auth_data
604
+ else
605
+ auth_name = ""
606
+ auth_data = ""
607
+ end
415
608
  p [auth_name, auth_data]
416
609
 
417
610
  handshake = Form::ClientHandshake.new(
data/lib/X11/form.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'ostruct'
2
1
 
3
2
  module X11
4
3
  module Form
@@ -82,14 +81,14 @@ module X11
82
81
  when :unused
83
82
  sz = s.size.respond_to?(:call) ? s.size.call(self) : s.size
84
83
  "\x00" * sz
85
- when :length
84
+ when :length, :format_length
86
85
  #p [s,value]
87
86
  #p [value.size]
88
87
  s.type_klass.pack(value.size)
89
88
  when :string
90
89
  s.type_klass.pack(value)
91
90
  when :list
92
- value.collect do |obj|
91
+ Array(value).collect do |obj|
93
92
  if obj.is_a?(BaseForm)
94
93
  obj.to_packet
95
94
  else
@@ -128,8 +127,17 @@ module X11
128
127
  when :length
129
128
  size = s.type_klass.unpack( socket.read(s.type_klass.size) )
130
129
  lengths[s.name] = size
130
+ when :format_length
131
+ size = s.type_klass.unpack( socket.read(s.type_klass.size) )
132
+ lengths[s.name] = case form.format
133
+ when 8 then size
134
+ when 16 then size*2
135
+ when 32 then size*4
136
+ else 0
137
+ end
131
138
  when :string
132
- val = s.type_klass.unpack(socket, lengths[s.name])
139
+ len = lengths[s.name]
140
+ val = s.type_klass.unpack(socket, len)
133
141
  form.instance_variable_set("@#{s.name}", val)
134
142
  when :list
135
143
  len = lengths[s.name]
@@ -178,12 +186,14 @@ module X11
178
186
  end
179
187
 
180
188
  def fields
181
- super+Array(@structs).dup.delete_if{|s| s.type == :unused or s.type == :length }
189
+ super+Array(@structs).dup.delete_if{|s| s.type == :unused or s.type == :length or s.type == :format_length}
182
190
  end
183
191
  end
184
192
  end
185
193
 
194
+ AtomAtom=4
186
195
  CardinalAtom=6
196
+ WindowAtom=33
187
197
 
188
198
  ##
189
199
  ## X11 Packet Defintions
@@ -248,9 +258,9 @@ module X11
248
258
  end
249
259
 
250
260
  class DisplayInfo < BaseForm
251
- field :release_number, Uint32
252
- field :resource_id_base, Uint32
253
- field :resource_id_mask, Uint32
261
+ field :release_number, Uint32
262
+ field :resource_id_base, Uint32
263
+ field :resource_id_mask, Uint32
254
264
  field :motion_buffer_size, Uint32
255
265
  field :vendor, Uint16, :length
256
266
  field :maximum_request_length, Uint16
@@ -259,11 +269,11 @@ module X11
259
269
  field :image_byte_order, Signifigance
260
270
  field :bitmap_bit_order, Signifigance
261
271
  field :bitmap_format_scanline_unit, Uint8
262
- field :bitmap_format_scanline_pad, Uint8
272
+ field :bitmap_format_scanline_pad, Uint8
263
273
  field :min_keycode, KeyCode
264
274
  field :max_keycode, KeyCode
265
275
  unused 4
266
- field :vendor, String8, :string
276
+ field :vendor, String8, :string
267
277
  field :formats, FormatInfo, :list
268
278
  field :screens, ScreenInfo, :list
269
279
  end
@@ -288,13 +298,13 @@ module X11
288
298
  # XRender structures
289
299
 
290
300
  class DirectFormat < BaseForm
291
- field :red, Uint16
292
- field :red_mask, Uint16
293
- field :green, Uint16
301
+ field :red, Uint16
302
+ field :red_mask, Uint16
303
+ field :green, Uint16
294
304
  field :green_mask, Uint16
295
- field :blue, Uint16
296
- field :blue_mask, Uint16
297
- field :alpha, Uint16
305
+ field :blue, Uint16
306
+ field :blue_mask, Uint16
307
+ field :alpha, Uint16
298
308
  field :alpha_mask, Uint16
299
309
  end
300
310
 
@@ -329,20 +339,38 @@ module X11
329
339
  # Requests
330
340
 
331
341
  CopyFromParent = 0
332
- InputOutput = 1
333
- InputOnly = 2
342
+ InputOutput = 1
343
+ InputOnly = 2
334
344
 
335
- CWBackPixel = 0x0002
345
+ CWBackPixmap = 0x0001
346
+ CWBackPixel = 0x0002
347
+ CWBorderPixmap= 0x0004
336
348
  CWBorderPixel = 0x0008
337
- CWEventMask = 0x0800
338
- CWColorMap = 0x2000
339
-
340
- KeyPressMask = 0x00001
341
- ButtonPressMask = 0x00004
342
- PointerMotionMask = 0x00040
343
- ExposureMask = 0x08000
344
- StructureNotifyMask = 0x20000
345
- SubstructureNotifyMask = 0x80000
349
+ CWBitGravity = 0x0010
350
+ CWWinGravity = 0x0020
351
+ CWBackingStore = 0x0040
352
+ CWBackingPlanes = 0x0080
353
+ CWBackingPixel = 0x0100
354
+ CWOverrideRedirect = 0x0200
355
+ CWSaveUnder = 0x0400
356
+ CWEventMask = 0x0800
357
+ CWColorMap = 0x2000
358
+
359
+ KeyPressMask = 0x000001
360
+ KeyReleaseMask = 0x000002
361
+ ButtonPressMask = 0x000004
362
+ ButtonReleaseMask = 0x000008
363
+ EnterWindowMask = 0x000010
364
+ LeaveWindowMask = 0x000020
365
+ PointerMotionMask = 0x000040
366
+ PointerMotionHintMask = 0x000080
367
+ Button1MotionMask = 0x000100
368
+ ExposureMask = 0x008000
369
+ StructureNotifyMask = 0x020000
370
+ SubstructureNotifyMask = 0x080000
371
+ SubstructureRedirectMask=0x100000
372
+ FocusChangeMask = 0x200000
373
+ PropertyChangeMask = 0x400000
346
374
 
347
375
  class CreateWindow < BaseForm
348
376
  field :opcode, Uint8, value: 1
@@ -361,6 +389,68 @@ module X11
361
389
  field :value_list, Uint32, :list
362
390
  end
363
391
 
392
+ class ChangeWindowAttributes < BaseForm
393
+ field :opcode, Uint8, value: 2
394
+ unused 1
395
+ field :request_length, Uint16, value: ->(cw) { 3 + cw.value_list.length }
396
+ field :window, Window
397
+ field :value_mask, Bitmask
398
+ field :value_list, Uint32, :list
399
+ end
400
+
401
+ class GetWindowAttributes < BaseForm
402
+ field :opcode, Uint8, value: 3
403
+ unused 1
404
+ field :request_length, Uint16, value: 2
405
+ field :window, Window
406
+ end
407
+
408
+ class WindowAttributes < BaseForm
409
+ field :reply, Uint8, value: 1
410
+ field :backing_store, Uint8
411
+ field :sequence_number, Uint16
412
+ field :reply_length, Uint32
413
+ field :visual, VisualID
414
+ field :wclass, Uint16
415
+ field :bit_gravity, Uint8
416
+ field :win_gravity, Uint8
417
+ field :backing_planes, Uint32
418
+ field :backing_pixel, Uint32
419
+ field :save_under, Bool
420
+ field :map_is_installed, Bool
421
+ field :map_state, Uint8
422
+ field :override_redirect, Bool
423
+ field :colormap, Colormap
424
+ field :all_event_masks, Uint32
425
+ field :your_event_masks, Uint32
426
+ field :do_not_propagate_mask, Uint16
427
+ unused 2
428
+ end
429
+
430
+ class DestroyWindow < BaseForm
431
+ field :opcode, Uint8, value: 4
432
+ unused 1
433
+ field :request_length, Uint16, value: 2
434
+ field :window, Window
435
+ end
436
+
437
+ class ChangeSaveSet < BaseForm
438
+ field :opcode, Uint8, value: 6
439
+ field :mode, Uint8
440
+ field :request_length, Uint16, value: 2
441
+ field :window, Window
442
+ end
443
+
444
+ class ReparentWindow < BaseForm
445
+ field :opcode, Uint8, value: 7
446
+ unused 1
447
+ field :request_length, Uint16, value: 4
448
+ field :window, Window
449
+ field :parent, Window
450
+ field :x, Int16
451
+ field :y, Int16
452
+ end
453
+
364
454
  class MapWindow < BaseForm
365
455
  field :opcode, Uint8, value: 8
366
456
  unused 1
@@ -368,6 +458,63 @@ module X11
368
458
  field :window, Window
369
459
  end
370
460
 
461
+ class UnmapWindow < BaseForm
462
+ field :opcode, Uint8, value: 10
463
+ unused 1
464
+ field :request_length, Uint16, value: 2
465
+ field :window, Window
466
+ end
467
+
468
+ class ConfigureWindow < BaseForm
469
+ field :opcode, Uint8, value: 12
470
+ unused 1
471
+ field :request_length, Uint16, value: ->(cw) { 3 + cw.values.length }
472
+ field :window, Window
473
+ field :value_mask, Uint16
474
+ unused 2
475
+ field :values, Uint32, :list
476
+ end
477
+
478
+ class GetGeometry < BaseForm
479
+ field :opcode, Uint8, value: 14
480
+ unused 1
481
+ field :request_length, Uint16, value: 2
482
+ field :drawable, Drawable
483
+ end
484
+
485
+ class Geometry < BaseForm
486
+ field :reply, Uint8, value: 1
487
+ field :depth, Uint8
488
+ field :sequence_number, Uint16
489
+ field :reply_length, Uint32
490
+ field :root, Window
491
+ field :x, Int16
492
+ field :y, Int16
493
+ field :width, Uint16
494
+ field :height, Uint16
495
+ field :border_width, Uint16
496
+ unused 10
497
+ end
498
+
499
+ class QueryTree < BaseForm
500
+ field :opcode, Uint8, value: 15
501
+ unused 1
502
+ field :request_length, Uint16, value: 2
503
+ field :window, Window
504
+ end
505
+
506
+ class QueryTreeReply < BaseForm
507
+ field :reply, Uint8, value: 1
508
+ unused 1
509
+ field :sequence_number, Uint16
510
+ field :reply_length, Uint32
511
+ field :root, Window
512
+ field :parent, Window
513
+ field :children, Uint16, :length
514
+ unused 14
515
+ field :children, Window, :list
516
+ end
517
+
371
518
  class InternAtom < BaseForm
372
519
  field :opcode, Uint8, value: 16
373
520
  field :only_if_exists, Bool
@@ -393,6 +540,22 @@ module X11
393
540
  unused 20
394
541
  end
395
542
 
543
+ class GetAtomName < BaseForm
544
+ field :opcode, Uint8, value: 17
545
+ unused 1
546
+ field :request_length, Uint16, value: 2
547
+ field :atom, Atom
548
+ end
549
+
550
+ class AtomName < Reply
551
+ unused 1
552
+ field :sequence_number, Uint16
553
+ field :reply_length, Uint32
554
+ field :name, Uint16, :length
555
+ unused 22
556
+ field :name, String8, :string
557
+ end
558
+
396
559
  Replace = 0
397
560
  Prepend = 1
398
561
  Append = 2
@@ -409,12 +572,60 @@ module X11
409
572
  field :type, Atom
410
573
  field :format, Uint8
411
574
  unused 3
412
- field :data, Uint32, value: ->(cp) {
413
- cp.data.length / 4
414
- }
575
+ field :data, Uint32, value: ->(cp) { cp.data.length / (cp.format/8) }
415
576
  field :data, Uint8, :list
416
577
  end
417
578
 
579
+ class GetProperty < BaseForm
580
+ field :opcode, Uint8, value: 20
581
+ field :delete, Bool
582
+ field :request_length, Uint16, value: 6
583
+ field :window, Window
584
+ field :property, Atom
585
+ field :type, Atom
586
+ field :long_offset, Uint32
587
+ field :long_length, Uint32
588
+ end
589
+
590
+ class Property < BaseForm
591
+ field :reply, Uint8, value: 1
592
+ field :format, Uint8
593
+ field :sequence_number, Uint16
594
+ field :reply_length, Uint32
595
+ field :type, Atom
596
+ field :bytes_after, Uint32
597
+ field :value, Uint32, :format_length
598
+ unused 12
599
+ field :value, String8, :string
600
+ end
601
+
602
+ class GrabButton < BaseForm
603
+ field :opcode, Uint8, value: 28
604
+ field :owner_events, Bool
605
+ field :request_length, Uint16, value: 6
606
+ field :grab_window, Window
607
+ field :event_mask, Uint16
608
+ field :pointer_mode, Uint8
609
+ field :keyboard_mode, Uint8
610
+ field :confine_to, Window
611
+ field :cursor, Cursor
612
+ field :button, Uint8
613
+ unused 1
614
+ field :modifiers, Uint16
615
+ end
616
+
617
+ class GrabKey < BaseForm
618
+ field :opcode, Uint8, value: 33
619
+ field :owner_event, Bool
620
+ field :request_length, Uint16, value: 4
621
+ field :grab_window, Window
622
+ field :modifiers, Uint16
623
+ field :keycode, Uint8
624
+ field :pointer_mode, Uint8
625
+ field :keyboard_mode, Uint8
626
+ unused 3
627
+ end
628
+
418
629
  class OpenFont < BaseForm
419
630
  field :opcode, Uint8, value: 45
420
631
  unused 1
@@ -516,11 +727,11 @@ module X11
516
727
  field :src_drawable, Drawable
517
728
  field :dst_drawable, Drawable
518
729
  field :gc, Gcontext
519
- field :src_x, Uint16
520
- field :src_y, Uint16
521
- field :dst_x, Uint16
522
- field :dst_y, Uint16
523
- field :width, Uint16
730
+ field :src_x, Uint16
731
+ field :src_y, Uint16
732
+ field :dst_x, Uint16
733
+ field :dst_y, Uint16
734
+ field :width, Uint16
524
735
  field :height, Uint16
525
736
  end
526
737
 
@@ -652,7 +863,7 @@ module X11
652
863
  field :sequence_number, Uint16
653
864
  end
654
865
 
655
- class PressEvent < SimpleEvent
866
+ class InputEvent < SimpleEvent
656
867
  field :time, Uint32
657
868
  field :root, Window
658
869
  field :event, Window
@@ -662,6 +873,32 @@ module X11
662
873
  field :event_x, Int16
663
874
  field :event_y, Int16
664
875
  field :state, Uint16
876
+ end
877
+
878
+ class EnterLeaveNotify < InputEvent
879
+ field :mode, Uint8
880
+ field :same_screen_or_focus, Uint8
881
+
882
+ def same_screen = same_screen_or_focus.anybit?(0x02)
883
+ def focus = same_screen_or_focus.anybit?(0x01)
884
+ end
885
+
886
+ class EnterNotify < EnterLeaveNotify
887
+ end
888
+
889
+ class LeaveNotify < EnterLeaveNotify
890
+ end
891
+
892
+ class FocusIn < SimpleEvent
893
+ field :event, Window
894
+ field :mode, Uint8
895
+ unused 23
896
+ end
897
+
898
+ class FocusOut < FocusIn
899
+ end
900
+
901
+ class PressEvent < InputEvent
665
902
  field :same_screen, Bool
666
903
  unused 1
667
904
  end
@@ -677,6 +914,34 @@ module X11
677
914
 
678
915
  class MotionNotify < PressEvent
679
916
  end
917
+
918
+ class ButtonRelease < PressEvent
919
+ end
920
+
921
+ class ReparentNotify < SimpleEvent
922
+ field :event, Window
923
+ field :window, Window
924
+ field :parent, Window
925
+ field :x, Int16
926
+ field :y, Int16
927
+ field :override_redirect, Bool
928
+ unused 11
929
+ end
930
+
931
+ class ConfigureRequest < Event # 23
932
+ field :stack_mode, Uint8
933
+ field :sequence_number, Uint16
934
+ field :parent, Window
935
+ field :window, Window
936
+ field :sibling, Window
937
+ field :x, Int16
938
+ field :y, Int16
939
+ field :width, Uint16
940
+ field :height, Uint16
941
+ field :border_width, Uint16
942
+ field :value_mask, Uint16
943
+ unused 4
944
+ end
680
945
 
681
946
  class Expose < SimpleEvent
682
947
  field :window, Window
@@ -695,14 +960,51 @@ module X11
695
960
  unused 21
696
961
  end
697
962
 
963
+ class CreateNotify < SimpleEvent # 16
964
+ field :parent, Window
965
+ field :window, Window
966
+ field :x, Int16
967
+ field :y, Int16
968
+ field :width, Uint16
969
+ field :height, Uint16
970
+ field :border_width, Uint16
971
+ field :override_redirect, Bool
972
+ end
973
+
974
+ class DestroyNotify < Event
975
+ unused 1
976
+ field :sequence_number, Uint16
977
+ field :event, Window
978
+ field :window, Window
979
+ unused 20
980
+ end
981
+
982
+ class UnmapNotify < Event
983
+ unused 1
984
+ field :sequence_number, Uint16
985
+ field :event, Window
986
+ field :window, Window
987
+ field :from_configure, Bool
988
+ unused 19
989
+ end
990
+
698
991
  class MapNotify < Event
699
992
  unused 1
700
993
  field :sequence_number, Uint16
701
994
  field :event, Window
995
+ field :window, Window
702
996
  field :override_redirect, Bool
703
997
  unused 19
704
998
  end
705
999
 
1000
+ class MapRequest < Event
1001
+ unused 1
1002
+ field :sequence_number, Uint16
1003
+ field :parent, Window
1004
+ field :window, Window
1005
+ unused 20
1006
+ end
1007
+
706
1008
  class ConfigureNotify < Event
707
1009
  unused 1
708
1010
  field :sequence_number, Uint16
@@ -717,6 +1019,24 @@ module X11
717
1019
  unused 5
718
1020
  end
719
1021
 
1022
+ class ClientMessage < Event
1023
+ field :format, Uint8
1024
+ field :sequence_number, Uint16
1025
+ field :window, Window
1026
+ field :type, Atom
1027
+ field :data, X11::Type::Message
1028
+ end
1029
+
1030
+ class PropertyNotify < Event # 28
1031
+ unused 1
1032
+ field :sequence_number, Uint16
1033
+ field :window, Window
1034
+ field :atom, Atom
1035
+ field :time, Uint32
1036
+ field :state, Uint8
1037
+ unused 15
1038
+ end
1039
+
720
1040
 
721
1041
  # XRender extension
722
1042
  # From https://cgit.freedesktop.org/xorg/proto/renderproto/tree/renderproto.h
data/lib/X11/keysyms.rb CHANGED
@@ -114,13 +114,18 @@ module X11
114
114
  0xff9d => :XK_KP_Begin,
115
115
  0xff9e => :XK_KP_Insert,
116
116
  0xff9f => :XK_KP_Delete,
117
- 0xffbd => :XK_KP_Equal,
118
117
  0xffaa => :XK_KP_Multiply,
119
118
  0xffab => :XK_KP_Add,
120
119
  0xffac => :XK_KP_Separator,
121
120
  0xffad => :XK_KP_Subtract,
122
121
  0xffae => :XK_KP_Decimal,
123
122
  0xffaf => :XK_KP_Divide,
123
+ 0xffbd => :XK_KP_Equal,
124
+ 0xffbe => :f1,
125
+ 0xffbf => :f2,
126
+ 0xffc0 => :f3,
127
+ 0xffc1 => :f4, # And so on
128
+
124
129
 
125
130
  0xffe1 => :XK_Shift_L,
126
131
  0xffe2 => :XK_Shift_R,
data/lib/X11/type.rb CHANGED
@@ -36,16 +36,23 @@ module X11
36
36
  define "Uint8", "C", 1
37
37
  define "Uint16", "S", 2
38
38
  define "Uint32", "L", 4
39
+
40
+ define "Message", "c*", 20
41
+
42
+ class Message
43
+ def self.pack(x) = x.b
44
+ def self.unpack(x) = x.b
45
+ def self.size = 20
46
+ def self.from_packet(sock) = sock.read(2).b
47
+ end
39
48
 
40
49
  class String8
41
50
  def self.pack(x)
42
51
  x.force_encoding("ASCII-8BIT") + "\x00"*(-x.length & 3)
43
52
  end
44
53
 
45
-
46
-
47
-
48
54
  def self.unpack(socket, size)
55
+ raise "Expected size for String8" if size.nil?
49
56
  val = socket.read(size)
50
57
  unused_padding = (4 - (size % 4)) % 4
51
58
  socket.read(unused_padding)
data/lib/X11/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module X11
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.5"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pure-x11
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vidar Hokstad
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-09-25 00:00:00.000000000 Z
12
+ date: 2023-12-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Pure Ruby X11 bindings
15
15
  email: