pure-x11 0.0.6 → 0.0.7

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: 927c52f35913e7d8bc466563bb5d238919c4a43d6a9f9fb1be8a6df4735cc5fb
4
- data.tar.gz: 3b92ed556881c32486ed189c9de27fdd373988379118fefdbd6f40ff6268c0e7
3
+ metadata.gz: 37b5a813f478de65ecb12e89bafd332ef219baabac729a1baf29cf016d055347
4
+ data.tar.gz: 357ef8cd392bad30e9c2d8a7b6771c5c4fd1dd68f3e77da1544cf93f22df14f0
5
5
  SHA512:
6
- metadata.gz: 580ab719f597acaecfa467389f26526dc50c1d25cacb14dbda9d63f61e3cb63f3665fd010408fc093501893a229a4b6a6f314734f6cf35786c58d965d0ec51cd
7
- data.tar.gz: 211b56d642b773c29769e9620c746a657596b6314e1d5a89487ace79bf29c6f01f4675ec2456a8668b8723912b2c81f2c95309dcdaf9eac459682150b884f726
6
+ metadata.gz: 81d50a93f9df23fe424f4dd62fe10fa09f840ab16eccb5de4d83b0d2f681b3cdb8fc9416e2b818f230399276974cac7455f38bfa1fe66c55968f70fc5c1661bb
7
+ data.tar.gz: 00bc7b7851c843a92988c23feacba461e6b9e1c2ef1f27b025c363f452f759492a30d4c1ff5d8117ba6bb4940eaebb19234c5fef9012d6cf8339a2ee143bf875
@@ -0,0 +1,13 @@
1
+
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'X11'
5
+
6
+ display = X11::Display.new
7
+
8
+ display.client_message(
9
+ mask: X11::Form::SubstructureNotifyMask | X11::Form::SubstructureRedirectMask,
10
+ type: :_NET_CURRENT_DESKTOP,
11
+ data: ARGV.shift.to_i
12
+ )
13
+
data/lib/X11/auth.rb CHANGED
@@ -11,14 +11,14 @@ module X11
11
11
  AUTHENTICATE = 2
12
12
 
13
13
  ADDRESS_TYPES = {
14
- 256 => :Local,
14
+ 0 => :Internet,
15
+ 1 => :DECnet,
16
+ 2 => :Chaos,
17
+ 252 => :LocalHost,
18
+ 253 => :Krb5Principal,
19
+ 254 => :Netname,
20
+ 256 => :Local,
15
21
  65535 => :Wild,
16
- 254 => :Netname,
17
- 253 => :Krb5Principal,
18
- 252 => :LocalHost,
19
- 0 => :Internet,
20
- 1 => :DECnet,
21
- 2 => :Chaos
22
22
  }
23
23
 
24
24
  AuthInfo = Struct.new :family, :address, :display, :auth_name, :auth_data
@@ -52,18 +52,15 @@ module X11
52
52
 
53
53
  # returns one entry from Xauthority file
54
54
  def read
55
- auth_info = [] << ADDRESS_TYPES[ @file.read(2).unpack('n').first ]
55
+ auth_info = [] << ADDRESS_TYPES[ @file.read(2).unpack1('n') ]
56
56
 
57
57
  4.times do
58
- length = @file.read(2).unpack('n').first
58
+ length = @file.read(2).unpack1('n')
59
59
  auth_info << @file.read(length)
60
60
  end
61
61
  AuthInfo[*auth_info]
62
62
  end
63
63
 
64
- def reset
65
- @file.seek(0, IO::SEEK_SET)
66
- end
67
-
64
+ def reset = @file.seek(0, IO::SEEK_SET)
68
65
  end
69
66
  end
data/lib/X11/display.rb CHANGED
@@ -17,6 +17,8 @@ module X11
17
17
  host, display_id, screen_id = $1, $2, $3
18
18
  family = nil
19
19
 
20
+ @debug = ENV["PUREX_DEBUG"].to_s.strip == "true"
21
+
20
22
  if host.empty?
21
23
  @socket = UNIXSocket.new("/tmp/.X11-unix/X#{display_id}")
22
24
  family = :Local
@@ -26,22 +28,27 @@ module X11
26
28
  family = :Internet
27
29
  end
28
30
 
29
- # FIXME
30
- authorize(host, family, display_id) rescue nil
31
+ authorize(host, family, display_id)
31
32
 
32
33
  @requestseq = 1
33
- @queue = []
34
-
35
- @extensions = {}
34
+ @rqueue = Queue.new # Read but not returned events
35
+ @wqueue = Queue.new
36
+ @extensions = {} # Known extensions
37
+ @atoms = {} # Interned atoms
36
38
 
37
- # Interned atoms
38
- @atoms = {}
39
+ start_io
39
40
  end
40
41
 
41
42
  def event_handler= block
42
43
  @event_handler= block
43
44
  end
44
45
 
46
+ def flush
47
+ while !@wqueue.empty?
48
+ sleep(0.01)
49
+ end
50
+ end
51
+
45
52
  def display_info
46
53
  @internal
47
54
  end
@@ -67,8 +74,15 @@ module X11
67
74
 
68
75
  def read_error data
69
76
  error = Form::Error.from_packet(StringIO.new(data))
77
+ # FIXME: Maybe make this configurable, as it means potentially
78
+ # keeping along really heavy requests. or alternative purge them
79
+ # more aggressively also when there are no errors, as otherwise
80
+ # the growth might be unbounded
81
+ error.request = @requests[error.sequence_number]
82
+ @requests.keys.find_all{|s| s <= error.sequence_number}.each do |s|
83
+ @requests.delete(s)
84
+ end
70
85
  STDERR.puts "ERROR: #{error.inspect}"
71
- raise error.inspect
72
86
  error
73
87
  end
74
88
 
@@ -126,22 +140,24 @@ module X11
126
140
  end
127
141
 
128
142
  def read_full_packet(len = 32)
129
- data = @socket.read_nonblock(32)
143
+ data = @socket.read(32)
130
144
  return nil if data.nil?
131
145
  while data.length < 32
132
146
  IO.select([@socket],nil,nil,0.001)
133
147
  data.concat(@socket.read_nonblock(32 - data.length))
134
148
  end
135
149
  return data
136
- rescue IO::WaitReadable
137
- return nil
138
150
  end
139
151
 
140
- def read_packet timeout=5.0
141
- IO.select([@socket],nil,nil, timeout)
152
+ def read_packet
142
153
  data = read_full_packet(32)
143
154
  return nil if data.nil?
144
155
 
156
+ # FIXME: Make it configurable.
157
+ @requests.keys.find_all{|s| s <= @requestseq - 50}.each do |s|
158
+ @requests.delete(s)
159
+ end
160
+
145
161
  # FIXME: What is bit 8 for? Synthentic?
146
162
  type = data.unpack("C").first & 0x7f
147
163
  case type
@@ -153,57 +169,100 @@ module X11
153
169
  end
154
170
  end
155
171
 
156
- def write_raw_packet(pkt)
157
- @requestseq += 1
158
- @socket.write(pkt)
159
- end
160
-
161
172
  def write_packet(*args)
162
173
  pkt = args.join
163
174
  pkt[2..3] = u16(pkt.length/4)
164
- write_raw_packet(pkt)
175
+ @wqueue << [nil,nil,pkt]
165
176
  end
166
177
 
167
178
  def write_request ob
168
- data = ob.to_packet if ob.respond_to?(:to_packet)
179
+ data = ob.to_packet(self) if ob.respond_to?(:to_packet)
169
180
  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
170
- write_raw_packet(data)
171
- end
172
-
173
- def write_sync(data, reply=nil)
174
- seq = @requestseq
175
- write_request(data)
176
- pkt = next_reply(seq)
177
- return nil if !pkt
178
- return pkt if pkt.is_a?(X11::Form::Error)
179
- pp reply
181
+ STDERR.puts "write_req: #{ob.inspect}" if @debug
182
+ @wqueue << [ob,nil,data]
183
+ end
184
+
185
+ def write_sync(ob, reply=nil)
186
+ data = ob.to_packet(self) if ob.respond_to?(:to_packet)
187
+ q = Queue.new
188
+ @wqueue << [ob,q,data]
189
+ STDERR.puts "write_sync_req: #{ob.inspect}" if @debug
190
+ pkt = q.shift
191
+ STDERR.puts "write_sync_rep: #{pkt.inspect}" if @debug
192
+ raise(pkt) if pkt.is_a?(X11::Form::Error)
193
+ return pkt if !pkt.is_a?(String)
180
194
  reply ? reply.from_packet(StringIO.new(pkt)) : pkt
181
195
  end
182
196
 
183
- def peek_packet
184
- !@queue.empty?
185
- end
197
+ def peek_packet = !@rqueue.empty?
198
+ def next_packet = @rqueue.shift
186
199
 
187
- def next_packet
188
- @queue.shift || read_packet
189
- end
200
+ def close = @rqueue.close
201
+
202
+ def start_io
203
+ @replies ||= {}
204
+ @requests ||= {}
205
+ # Read thread.
206
+ # FIXME: Drop the select.
207
+ rt = Thread.new do
208
+ while pkt = read_packet
209
+ #STDERR.puts "read: #{pkt.inspect}"
210
+ if !pkt
211
+ sleep 0.1
212
+ elsif pkt.is_a?(String)
213
+ # This is a reply. We need the sequence number.
214
+ #
215
+ seq = pkt.unpack1("@2S")
216
+ STDERR.puts " - seq= #{seq}" if @debug
217
+ STDERR.puts @replies.inspect if @debug
218
+ if @replies[seq]
219
+ q = @replies.delete(seq)
220
+ STDERR.puts " - reply to #{q}" if @debug
221
+ q << pkt
222
+ end
223
+ elsif pkt.is_a?(X11::Form::Error)
224
+ if @replies[pkt.sequence_number]
225
+ q = @replies.delete(pkt.sequence_number)
226
+ q << pkt
227
+ else
228
+ @rqueue << pkt
229
+ end
230
+ else
231
+ @rqueue << pkt
232
+ end
233
+ end
234
+ @rqueue.close
235
+ @replies.values.each(&:close)
236
+ end
190
237
 
191
- def next_reply(errseq)
192
- # FIXME: This is totally broken
193
- while pkt = read_packet
194
- if pkt.is_a?(String)
195
- return pkt
196
- elsif pkt.is_a?(X11::Form::Error) && pkt.sequence_number == errseq
197
- return pkt
198
- else
199
- @queue.push(pkt)
238
+ # Write thread
239
+ wt = Thread.new do
240
+ while msg = @wqueue.shift
241
+ ob, q, data = *msg
242
+ @requests[@requestseq] = ob
243
+ @replies[@requestseq] = q if q
244
+ @requestseq = (@requestseq + 1) % 65536
245
+ @socket.write(data)
200
246
  end
201
247
  end
248
+
249
+ at_exit do
250
+ flush
251
+ @rqueue.close
252
+ @wqueue.close
253
+ # We kill this because it may be stuck in a read
254
+ # we'll never care about
255
+ Thread.kill(rt)
256
+
257
+ # We wait for this to finish because otherwise we may
258
+ # lose side-effects
259
+ wt.join
260
+ end
202
261
  end
203
-
262
+
204
263
  def run
205
264
  loop do
206
- pkt = read_packet
265
+ pkt = next_packet
207
266
  return if !pkt
208
267
  yield(pkt)
209
268
  end
@@ -214,13 +273,15 @@ module X11
214
273
  d.depth == depth }.visuals.find{|v| v.qlass = qlass }
215
274
  end
216
275
 
276
+ def default_root = screens.first.root
277
+
217
278
  # Requests
218
279
  def create_window(x,y,w,h,
219
280
  values: {},
220
281
  depth: 32, parent: nil, border_width: 0, wclass: X11::Form::InputOutput, visual: nil
221
282
  )
222
283
  wid = new_id
223
- parent ||= screens.first.root
284
+ parent ||= default_root
224
285
 
225
286
  if visual.nil?
226
287
  visual = find_visual(0, depth).visual_id
@@ -255,6 +316,12 @@ module X11
255
316
 
256
317
  def atom(name)
257
318
  return name if name.is_a?(Integer) # Allow atom(atom_integer_or_symbol)
319
+ begin
320
+ return Form::Atoms.const_get(name.to_sym) if Form::Atoms.const_defined?(name.to_sym)
321
+ rescue
322
+ # const_defined? will throw if name isn't a valid constant name, but
323
+ # that's fine
324
+ end
258
325
  name = name.to_sym
259
326
  intern_atom(false, name) if !@atoms[name]
260
327
  @atoms[name]
@@ -343,7 +410,10 @@ module X11
343
410
  def u8(*args) = args.pack("c*")
344
411
  def u16(*args) = args.pack("v*")
345
412
  def u32(*args) = args.pack("V*")
346
- def atom_enum(val) = open_enum(val, {cardinal: Form::CardinalAtom, atom: Form::AtomAtom, window: Form::WindowAtom})
413
+ def atom_enum(val)
414
+ open_enum(val, {cardinal: Form::CardinalAtom, atom: Form::AtomAtom, window: Form::WindowAtom}) || atom(val)
415
+ end
416
+
347
417
  def window(*args)
348
418
  args.each {|a| raise "Window expected" if a.nil? }
349
419
  u32(*args)
@@ -354,7 +424,7 @@ module X11
354
424
  def set_input_focus(revert_to, focus, time=:now)
355
425
  # FIXME: This is an experiment.
356
426
  # Upside: Simpler. Downside: Doesn't work server-side.
357
- #
427
+ # Probably a bad idea.
358
428
  revert_to = open_enum(revert_to, {none: 0, pointer_root: 1, parent: 2})
359
429
  focus = open_enum(focus, {none: 0, pointer_root: 1 })
360
430
  time = open_enum(time, {current_time: 0, now: 0})
@@ -394,9 +464,8 @@ module X11
394
464
  def configure_window(window, x: nil, y: nil, width: nil, height: nil,
395
465
  border_width: nil, sibling: nil, stack_mode: nil)
396
466
 
397
- mask = 0
398
467
  values = []
399
-
468
+ mask = 0
400
469
  mask |= set_value(values, 0x001, x)
401
470
  mask |= set_value(values, 0x002, y)
402
471
  mask |= set_value(values, 0x004, width)
@@ -419,7 +488,9 @@ module X11
419
488
  end
420
489
 
421
490
 
422
- def create_gc(window, foreground: nil, background: nil)
491
+ def create_gc(window, foreground: nil, background: nil,
492
+ graphics_exposures: nil
493
+ )
423
494
  mask = 0
424
495
  args = []
425
496
 
@@ -428,12 +499,27 @@ module X11
428
499
  # https://tronche.com/gui/x/xlib/GC/manipulating.html#XGCValues
429
500
  mask |= set_value(args, 0x04, foreground)
430
501
  mask |= set_value(args, 0x08, background)
502
+ mask |= set_value(args, 0x10000, graphics_exposures)
431
503
 
432
504
  gc = new_id
433
505
  write_request(X11::Form::CreateGC.new(gc, window, mask, args))
434
506
  gc
435
507
  end
436
508
 
509
+ def send_event(...) = write_request(Form::SendEvent.new(...))
510
+ def client_message(window: default_root, type: :ClientMessage, format: 32, destination: default_root, mask: 0, data: [], propagate: true)
511
+ f = {8 => "C20", 16 => "S10", 32 => "L5"}[format]
512
+ p f
513
+ data = (Array(data).map{|item|atom(item)} +[0]*20).pack(f)
514
+ event = Form::ClientMessage.new(
515
+ format, 0, window, atom(type), data
516
+ )
517
+ event.code =33
518
+ pp event
519
+
520
+ send_event(propagate, destination, mask, event)
521
+ end
522
+
437
523
  def put_image(*args) = write_request(X11::Form::PutImage.new(*args))
438
524
  def clear_area(*args) = write_request(X11::Form::ClearArea.new(*args))
439
525
  def copy_area(*args) = write_request(X11::Form::CopyArea.new(*args))
@@ -499,19 +585,19 @@ module X11
499
585
  end
500
586
  when :rgb24
501
587
  @rgb24 ||= formats.formats.find do |f|
502
- f.type == 1 &&
588
+ f.type == 1 &&
503
589
  f.depth == 24 &&
504
590
  f.direct.red == 16 &&
505
- f.direct.green == 8 &&
591
+ f.direct.green == 8 &&
506
592
  f.direct.blue == 0
507
593
  end
508
594
  when :argb24
509
595
  @argb24 ||= formats.formats.find do |f|
510
- f.type == 1 &&
596
+ f.type == 1 &&
511
597
  f.depth == 32 &&
512
598
  f.direct.alpha == 24 &&
513
599
  f.direct.red == 16 &&
514
- f.direct.green == 8 &&
600
+ f.direct.green == 8 &&
515
601
  f.direct.blue == 0
516
602
  end
517
603
  else
@@ -570,7 +656,6 @@ module X11
570
656
  auth_name = ""
571
657
  auth_data = ""
572
658
  end
573
- p [auth_name, auth_data]
574
659
 
575
660
  handshake = Form::ClientHandshake.new(
576
661
  Protocol::BYTE_ORDER,
@@ -580,7 +665,7 @@ module X11
580
665
  auth_data
581
666
  )
582
667
 
583
- @socket.write(handshake.to_packet)
668
+ @socket.write(handshake.to_packet(self))
584
669
 
585
670
  data = @socket.read(1)
586
671
  raise AuthorizationError, "Failed to read response from server" if !data
data/lib/X11/form.rb CHANGED
@@ -44,7 +44,7 @@ module X11
44
44
  end
45
45
  end
46
46
 
47
- def to_packet
47
+ def to_packet(dpy)
48
48
  # fetch class level instance variable holding defined fields
49
49
  structs = self.class.structs
50
50
 
@@ -64,10 +64,10 @@ module X11
64
64
  #p [s,value]
65
65
 
66
66
  if value.is_a?(BaseForm)
67
- v = value.to_packet
67
+ v = value.to_packet(dpy)
68
68
  else
69
69
  #p [s,value]
70
- v = s.type_klass.pack(value)
70
+ v = s.type_klass.pack(value, dpy)
71
71
  end
72
72
  #p v
73
73
  v
@@ -77,15 +77,15 @@ module X11
77
77
  when :length, :format_length
78
78
  #p [s,value]
79
79
  #p [value.size]
80
- s.type_klass.pack(value.size)
80
+ s.type_klass.pack(value.size, dpy)
81
81
  when :string
82
- s.type_klass.pack(value)
82
+ s.type_klass.pack(value, dpy)
83
83
  when :list
84
84
  Array(value).collect do |obj|
85
85
  if obj.is_a?(BaseForm)
86
- obj.to_packet
86
+ obj.to_packet(dpy)
87
87
  else
88
- s.type_klass.pack(obj)
88
+ s.type_klass.pack(obj, dpy)
89
89
  end
90
90
  end
91
91
  end
@@ -184,6 +184,29 @@ module X11
184
184
  end
185
185
  end
186
186
 
187
+ # # Predefined constants, that can be used in the form of symbols
188
+
189
+ module Atoms
190
+ PRIMARY = 1
191
+ SECONDARY = 2
192
+ ARC = 3
193
+ ATOM = 4
194
+ BITMAP = 5
195
+ CARDINAL = 6
196
+ COLORMAP = 7
197
+ CURSOR = 8
198
+ #...
199
+ STRING = 31
200
+ VISUALID = 32
201
+ WINDOW = 33
202
+ WM_COMMAND = 34
203
+ WM_HINTS = 35
204
+ end
205
+
206
+ PointerWindow = 0
207
+ InputFocus = 1
208
+
209
+ # FIXME: Deprecated in favour of the Constants module
187
210
  AtomAtom=4
188
211
  CardinalAtom=6
189
212
  WindowAtom=33
@@ -286,6 +309,9 @@ module X11
286
309
  field :minor_opcode, Uint16
287
310
  field :major_opcode, Uint8
288
311
  unused 21
312
+
313
+ # The original request
314
+ attr_accessor :request
289
315
  end
290
316
 
291
317
  # XRender structures
@@ -329,8 +355,9 @@ module X11
329
355
  field :colormap, Colormap
330
356
  end
331
357
 
332
- # Requests
358
+ # # Requests
333
359
 
360
+ # Constants, p112 onwards
334
361
  CopyFromParent = 0
335
362
  InputOutput = 1
336
363
  InputOnly = 2
@@ -358,12 +385,17 @@ module X11
358
385
  PointerMotionMask = 0x000040
359
386
  PointerMotionHintMask = 0x000080
360
387
  Button1MotionMask = 0x000100
388
+ # 0x200 .. 0x40000; page 113
361
389
  ExposureMask = 0x008000
390
+ VisibilityChangeMask = 0x010000
362
391
  StructureNotifyMask = 0x020000
392
+ ResizeRedirectMask = 0x040000
363
393
  SubstructureNotifyMask = 0x080000
364
394
  SubstructureRedirectMask=0x100000
365
395
  FocusChangeMask = 0x200000
366
396
  PropertyChangeMask = 0x400000
397
+ ColormapChangeMask = 0x800000
398
+ OwnerGrabButtonMask = 0x100000
367
399
 
368
400
  class CreateWindow < BaseForm
369
401
  field :opcode, Uint8, value: 1
@@ -592,6 +624,15 @@ module X11
592
624
  field :value, String8, :string
593
625
  end
594
626
 
627
+ class SendEvent < BaseForm
628
+ field :opcode, Uint8, value: 25
629
+ field :propagate, Bool
630
+ field :request_length, Uint16, value: 11
631
+ field :destination, Window
632
+ field :event_mask, Uint32
633
+ field :event, Uint32 # FIXME: This is wrong, and will break on parsing.
634
+ end
635
+
595
636
  class GrabButton < BaseForm
596
637
  field :opcode, Uint8, value: 28
597
638
  field :owner_events, Bool
@@ -678,6 +719,7 @@ module X11
678
719
  ForegroundMask = 0x04
679
720
  BackgroundMask = 0x08
680
721
  FontMask = 0x4000
722
+ GraphicsExposures = 0x10000
681
723
 
682
724
  class CreateGC < BaseForm
683
725
  field :opcode, Uint8, value: 55
@@ -1002,6 +1044,7 @@ module X11
1002
1044
  unused 1
1003
1045
  field :sequence_number, Uint16
1004
1046
  field :event, Window
1047
+ field :window, Window
1005
1048
  field :above_sibling, Window
1006
1049
  field :x, Int16
1007
1050
  field :y, Int16
data/lib/X11/protocol.rb CHANGED
@@ -1,14 +1,12 @@
1
1
  module X11
2
2
  module Protocol
3
- # endiness of your machine
3
+ # endianess of your machine
4
4
  BYTE_ORDER = case [1].pack("L")
5
- when "\0\0\0\1"
6
- "B".ord
7
- when "\1\0\0\0"
8
- "l".ord
5
+ when "\0\0\0\1" then "B".ord
6
+ when "\1\0\0\0" then "l".ord
9
7
  else
10
8
  raise ByteOrderError.new "Cannot determine byte order"
11
- end
9
+ end
12
10
 
13
11
  MAJOR = 11
14
12
  MINOR = 0
data/lib/X11/screen.rb CHANGED
@@ -7,25 +7,11 @@ module X11
7
7
  @internal = data
8
8
  end
9
9
 
10
- def root
11
- @internal.root
12
- end
13
-
14
- def root_depth
15
- @internal.root_depth
16
- end
17
-
18
- def root_visual
19
- @internal.root_visual
20
- end
21
-
22
- def width
23
- @internal.width_in_pixels
24
- end
25
-
26
- def height
27
- @internal.height_in_pixels
28
- end
10
+ def root = @internal.root
11
+ def root_depth = @internal.root_depth
12
+ def root_visual = @internal.root_visual
13
+ def width = @internal.width_in_pixels
14
+ def height = @internal.height_in_pixels
29
15
 
30
16
  def to_s
31
17
  "#<X11::Screen(#{id}) width=#{width} height=#{height}>"
data/lib/X11/type.rb CHANGED
@@ -11,7 +11,7 @@ module X11
11
11
 
12
12
  def self.config(d,b) = (@directive, @bytesize = d,b)
13
13
 
14
- def self.pack(x)
14
+ def self.pack(x, dpy)
15
15
  if x.is_a?(Symbol)
16
16
  if (t = X11::Form.const_get(x)) && t.is_a?(Numeric)
17
17
  x = t
@@ -27,7 +27,6 @@ module X11
27
27
  def self.from_packet(sock) = unpack(sock.read(size))
28
28
  end
29
29
 
30
- # Primitive Types
31
30
  class Int8 < BaseType; config("c",1); end
32
31
  class Int16 < BaseType; config("s",2); end
33
32
  class Int32 < BaseType; config("l",4); end
@@ -36,16 +35,14 @@ module X11
36
35
  class Uint32 < BaseType; config("L",4); end
37
36
 
38
37
  class Message
39
- def self.pack(x) = x.b
40
- def self.unpack(x) = x.b
41
- def self.size = 20
38
+ def self.pack(x,dpy) = x.b
39
+ def self.unpack(x) = x.b
40
+ def self.size = 20
42
41
  def self.from_packet(sock) = sock.read(2).b
43
42
  end
44
43
 
45
44
  class String8
46
- def self.pack(x)
47
- x.b + "\x00"*(-x.length & 3)
48
- end
45
+ def self.pack(x, dpy) = (x.b + "\x00"*(-x.length & 3))
49
46
 
50
47
  def self.unpack(socket, size)
51
48
  raise "Expected size for String8" if size.nil?
@@ -57,7 +54,7 @@ module X11
57
54
  end
58
55
 
59
56
  class String16
60
- def self.pack(x)
57
+ def self.pack(x, dpy)
61
58
  x.encode("UTF-16BE").b + "\x00\x00"*(-x.length & 1)
62
59
  end
63
60
 
@@ -71,13 +68,13 @@ module X11
71
68
 
72
69
 
73
70
  class String8Unpadded
74
- def self.pack(x) = x
71
+ def self.pack(x,dpy) = x
75
72
  def self.unpack(socket, size) = socket.read(size)
76
73
  end
77
74
 
78
75
  class Bool
79
- def self.pack(x) = (x ? "\x01" : "\x00")
80
- def self.unpack(str) = (str[0] == "\x01")
76
+ def self.pack(x, dpy) = (x ? "\x01" : "\x00")
77
+ def self.unpack(str) = (str[0] == "\x01")
81
78
  def self.size = 1
82
79
  end
83
80
 
@@ -96,10 +93,16 @@ module X11
96
93
  Colormap = Uint32
97
94
  Drawable = Uint32
98
95
  Fontable = Uint32
99
- Atom = Uint32
100
96
  VisualID = Uint32
101
97
  Mask = Uint32
102
98
  Timestamp = Uint32
103
99
  Keysym = Uint32
100
+
101
+ class Atom
102
+ def self.pack(x,dpy) = [dpy.atom(x)].pack("L")
103
+ def self.unpack(x) = x.nil? ? nil : x.unpack1("L")
104
+ def self.size = 4
105
+ def self.from_packet(sock) = unpack(sock.read(size))
106
+ end
104
107
  end
105
108
  end
data/lib/X11/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module X11
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
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.6
4
+ version: 0.0.7
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-12-28 00:00:00.000000000 Z
12
+ date: 2024-01-11 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Pure Ruby X11 bindings
15
15
  email:
@@ -25,6 +25,7 @@ files:
25
25
  - README.md
26
26
  - Rakefile
27
27
  - docs/protocol.pdf
28
+ - example/client_message.rb
28
29
  - example/genie.png
29
30
  - example/test.rb
30
31
  - lib/X11.rb