pure-x11 0.0.2 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: