pure-x11 0.0.4 → 0.0.6

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: 51d974fee51d60b334a5e5f26bb5e0d90f8628e09930da7bb6c97145b3718ed9
4
- data.tar.gz: 2312f1c9f7e0d2b5391bb15aab15805e802635d53d6fe1d90cf22f0c2112b117
3
+ metadata.gz: 927c52f35913e7d8bc466563bb5d238919c4a43d6a9f9fb1be8a6df4735cc5fb
4
+ data.tar.gz: 3b92ed556881c32486ed189c9de27fdd373988379118fefdbd6f40ff6268c0e7
5
5
  SHA512:
6
- metadata.gz: 226fbfc35ff75f2fa95fabf09a7d0e4c72cd99f1678cd607e8421ed26750118e40291686a582c01b0ae296dfcefc5e7038bd3d3025f9b678e5a1fa35c2465135
7
- data.tar.gz: 69363b78df087ea43799f06c8477d008d15b721bcd604a52e1eb3b33411a102fcf4d33f3262ac0c0de5fa76de9262d489eaaca85e043f5251bb41563959970fd
6
+ metadata.gz: 580ab719f597acaecfa467389f26526dc50c1d25cacb14dbda9d63f61e3cb63f3665fd010408fc093501893a229a4b6a6f314734f6cf35786c58d965d0ec51cd
7
+ data.tar.gz: 211b56d642b773c29769e9620c746a657596b6314e1d5a89487ace79bf29c6f01f4675ec2456a8668b8723912b2c81f2c95309dcdaf9eac459682150b884f726
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
+ vendor/
2
+
1
3
  # rcov generated
2
4
  coverage
3
5
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pure-x11 (0.0.4)
4
+ pure-x11 (0.0.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/example/test.rb CHANGED
@@ -13,37 +13,37 @@ require 'X11'
13
13
  dpy = display = X11::Display.new
14
14
  screen = dpy.screens.first
15
15
  root = screen.root
16
- wid = display.new_id
17
16
 
18
- dpy.create_window(
19
- screen.root_depth, wid, root,
17
+ wid = dpy.create_window(
20
18
  0, 0, # x,y
21
19
  1000, 600, # w,h
22
- 0,
23
- X11::Form::InputOutput,
24
- X11::Form::CopyFromParent,
25
- X11::Form::CWBackPixel |
26
- X11::Form::CWEventMask,
27
- [0x0, # RGB background
28
- X11::Form::SubstructureNotifyMask |
29
- X11::Form::StructureNotifyMask | ## Move
30
- X11::Form::ExposureMask |
31
- X11::Form::KeyPressMask |
32
- X11::Form::ButtonPressMask
33
- ]
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
+ }
34
31
  )
32
+ #dpy.next_packet
33
+ #exit(0)
35
34
 
36
35
  def set_window_opacity(dpy, wid, opacity)
37
36
  dpy.change_property(
38
- X11::Form::Replace,
39
- wid, dpy.atom(:_NET_WM_WINDOW_OPACITY),
40
- X11::Form::CardinalAtom, 32,
41
- [(0xffffffff * opacity).to_i].pack("N").split(//).map(&:ord)
37
+ :replace,
38
+ wid, "_NET_WM_WINDOW_OPACITY",
39
+ :cardinal, 32,
40
+ [(0xffffffff * opacity).to_i].pack("V").unpack("C*")
42
41
  )
43
42
  end
44
43
 
45
44
 
46
45
  set_window_opacity(dpy, wid, 0.8)
46
+
47
47
  #p dpy.display_info
48
48
 
49
49
  #reply = dpy.query_extension("XKEYBOARD")
@@ -143,7 +143,7 @@ def render_glyph(display, wid, x,y, ch)
143
143
  #p img
144
144
  # p ch
145
145
  display.put_image(
146
- X11::Form::ZPixmap, wid, $gc2,
146
+ :ZPixmap, wid, $gc2,
147
147
  mtx.min_width,mtx.min_height,
148
148
  x, y - mtx.y_offset, 0, depth, data
149
149
  )
@@ -158,12 +158,12 @@ def render_str(display, wid, x,y, str)
158
158
  end
159
159
 
160
160
  def redraw(dpy, wid, gc)
161
- dpy.poly_fill_rectangle(wid, gc, [X11::Form::Rectangle.new(20,20, 60, 80)])
161
+ dpy.poly_fill_rectangle(wid, gc, [20,20, 60, 80])
162
162
  dpy.clear_area(false, wid, 30, 30, 5, 5)
163
163
  dpy.image_text16(wid, $gc2, 30, 70, "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ")
164
164
  #"\u25f0\u25ef Hello World")
165
165
  dpy.put_image(
166
- X11::Form::ZPixmap, wid, $gc2,
166
+ :ZPixmap, wid, $gc2,
167
167
  $png.width, $png.height, 80, 120, 0, 24, $data
168
168
  )
169
169
  render_str(dpy, wid, 30,90, 'HelloWorld')
data/lib/X11/display.rb CHANGED
@@ -68,6 +68,7 @@ module X11
68
68
  def read_error data
69
69
  error = Form::Error.from_packet(StringIO.new(data))
70
70
  STDERR.puts "ERROR: #{error.inspect}"
71
+ raise error.inspect
71
72
  error
72
73
  end
73
74
 
@@ -80,28 +81,47 @@ module X11
80
81
  end
81
82
 
82
83
  def read_event type, data, event_class
84
+ io = StringIO.new(data)
83
85
  case type
84
- when 2
85
- return Form::KeyPress.from_packet(StringIO.new(data))
86
- when 3
87
- return Form::KeyRelease.from_packet(StringIO.new(data))
88
- when 4
89
- return Form::ButtonPress.from_packet(StringIO.new(data))
90
- when 5
91
- return Form::ButtonRelease.from_packet(StringIO.new(data))
92
- when 6
93
- return Form::MotionNotify.from_packet(StringIO.new(data))
94
- when 12
95
- return Form::Expose.from_packet(StringIO.new(data))
96
- when 14
97
- return Form::NoExposure.from_packet(StringIO.new(data))
98
- when 19
99
- return Form::MapNotify.from_packet(StringIO.new(data))
100
- when 22
101
- 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(io)
120
+ # FIXME: 34: MappingNotify
102
121
  else
103
122
  STDERR.puts "FIXME: Event: #{type}"
104
123
  STDERR.puts "EVENT: #{data.inspect}"
124
+ data
105
125
  end
106
126
  end
107
127
 
@@ -122,34 +142,41 @@ module X11
122
142
  data = read_full_packet(32)
123
143
  return nil if data.nil?
124
144
 
125
- type = data.unpack("C").first
145
+ # FIXME: What is bit 8 for? Synthentic?
146
+ type = data.unpack("C").first & 0x7f
126
147
  case type
127
- when 0
128
- read_error(data)
129
- when 1
130
- read_reply(data)
131
- when 2..34
132
- 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)
133
151
  else
134
- raise ProtocolError, "Unsupported reply type: #{type}"
152
+ raise ProtocolError, "Unsupported reply type: #{type} #{data.inspect}"
135
153
  end
136
154
  end
137
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
+
138
167
  def write_request ob
139
- #p data
140
- #p [:write_request, @requestseq, ob.class]
141
168
  data = ob.to_packet if ob.respond_to?(:to_packet)
142
- #p [:AddGlyph,data] if ob.is_a?(X11::Form::XRenderAddGlyphs)
143
- #p [ob.request_length.to_i*4, data.size]
144
169
  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
145
- @requestseq += 1
146
- @socket.write(data)
170
+ write_raw_packet(data)
147
171
  end
148
172
 
149
173
  def write_sync(data, reply=nil)
174
+ seq = @requestseq
150
175
  write_request(data)
151
- pkt = next_reply
176
+ pkt = next_reply(seq)
152
177
  return nil if !pkt
178
+ return pkt if pkt.is_a?(X11::Form::Error)
179
+ pp reply
153
180
  reply ? reply.from_packet(StringIO.new(pkt)) : pkt
154
181
  end
155
182
 
@@ -161,17 +188,19 @@ module X11
161
188
  @queue.shift || read_packet
162
189
  end
163
190
 
164
- def next_reply
191
+ def next_reply(errseq)
165
192
  # FIXME: This is totally broken
166
193
  while pkt = read_packet
167
194
  if pkt.is_a?(String)
168
195
  return pkt
196
+ elsif pkt.is_a?(X11::Form::Error) && pkt.sequence_number == errseq
197
+ return pkt
169
198
  else
170
199
  @queue.push(pkt)
171
200
  end
172
201
  end
173
202
  end
174
-
203
+
175
204
  def run
176
205
  loop do
177
206
  pkt = read_packet
@@ -193,12 +222,10 @@ module X11
193
222
  wid = new_id
194
223
  parent ||= screens.first.root
195
224
 
196
-
197
225
  if visual.nil?
198
226
  visual = find_visual(0, depth).visual_id
199
227
  end
200
228
 
201
-
202
229
  values[X11::Form::CWColorMap] ||= create_colormap(0, parent, visual)
203
230
 
204
231
  values = values.sort_by{_1[0]}
@@ -212,26 +239,30 @@ module X11
212
239
  return wid
213
240
  end
214
241
 
242
+ def get_window_attributes(wid)
243
+ write_sync( Form::GetWindowAttributes.new(wid), Form::WindowAttributes )
244
+ end
245
+
215
246
  def change_window_attributes(wid,
216
247
  values: {})
217
248
  values = values.sort_by{_1[0]}
218
249
  mask = values.inject(0) {|acc,v| (acc | v[0]) }
219
250
  values = values.map{_1[1]}
220
- write_request(
221
- X11::Form::ChangeWindowAttributes.new(wid, mask, values)
222
- )
251
+ write_request(Form::ChangeWindowAttributes.new(wid, mask, values))
223
252
  end
224
253
 
254
+ def select_input(w, events) = change_window_attributes(w, values: {Form::CWEventMask => events})
255
+
225
256
  def atom(name)
257
+ return name if name.is_a?(Integer) # Allow atom(atom_integer_or_symbol)
258
+ name = name.to_sym
226
259
  intern_atom(false, name) if !@atoms[name]
227
260
  @atoms[name]
228
261
  end
229
262
 
230
263
  def query_extension(name)
231
- r = write_sync(X11::Form::QueryExtension.new(name), X11::Form::QueryExtensionReply)
232
- @extensions[name] = {
233
- major: r.major_opcode
234
- }
264
+ r = write_sync(Form::QueryExtension.new(name), Form::QueryExtensionReply)
265
+ @extensions[name] = { major: r.major_opcode }
235
266
  r
236
267
  end
237
268
 
@@ -244,66 +275,106 @@ module X11
244
275
  end
245
276
 
246
277
  def intern_atom(flag, name)
247
- reply = write_sync(X11::Form::InternAtom.new(flag, name.to_s),
248
- X11::Form::InternAtomReply)
278
+ reply = write_sync(Form::InternAtom.new(flag, name.to_s),Form::InternAtomReply)
249
279
  if reply
250
280
  @atoms[name.to_sym] = reply.atom
251
281
  end
252
282
  end
253
283
 
254
- def destroy_window(window)
255
- write_request(X11::Form::DestroyWindow.new(window))
256
- end
257
-
258
- def get_geometry(drawable)
259
- write_sync(X11::Form::GetGeometry.new(drawable), X11::Form::Geometry)
260
- end
284
+ def get_atom_name(atom) = write_sync(Form::GetAtomName.new(atom), Form::AtomName)&.name
285
+ def destroy_window(window) = write_request(Form::DestroyWindow.new(window))
286
+ def get_geometry(drawable) = write_sync(Form::GetGeometry.new(drawable), Form::Geometry)
261
287
 
262
288
  def get_keyboard_mapping(min_keycode=display_info.min_keycode, count= display_info.max_keycode - min_keycode)
263
- write_sync(X11::Form::GetKeyboardMapping.new(min_keycode, count), X11::Form::GetKeyboardMappingReply)
289
+ write_sync(Form::GetKeyboardMapping.new(min_keycode, count), Form::GetKeyboardMappingReply)
264
290
  end
265
291
 
266
292
  def create_colormap(alloc, window, visual)
267
293
  mid = new_id
268
- write_request(X11::Form::CreateColormap.new(alloc, mid, window, visual))
294
+ write_request(Form::CreateColormap.new(alloc, mid, window, visual))
269
295
  mid
270
296
  end
271
297
 
272
- def change_property(*args)
273
- write_request(X11::Form::ChangeProperty.new(*args))
298
+ def get_property(window, property, type, offset: 0, length: 4, delete: false)
299
+ property = atom(property)
300
+ type = atom_enum(type)
301
+
302
+ result = write_sync(Form::GetProperty.new(
303
+ delete, window, property, type, offset, length
304
+ ), Form::Property)
305
+
306
+ if result && result.format != 0
307
+ case result.format
308
+ when 16
309
+ result.value = result.value.unpack("v")
310
+ result.value = result.value.first if length == 2
311
+ when 32
312
+ result.value = result.value.unpack("V")
313
+ result.value = result.value.first if length == 4
314
+ end
315
+ elsif result
316
+ result.value = nil
317
+ end
318
+ result
274
319
  end
320
+
321
+ def change_property(mode, window, property, type, format, data)
322
+ property = atom(property.to_sym) if property.is_a?(Symbol) || property.is_a?(String)
275
323
 
276
- def list_fonts(*args)
277
- write_sync(X11::Form::ListFonts.new(*args),
278
- X11::Form::ListFontsReply)
324
+ mode = open_enum(mode, {replace: 0, prepend: 1, append: 2})
325
+ type = atom_enum(type)
326
+ write_request(Form::ChangeProperty.new(mode, window, property, type, format, data))
279
327
  end
280
328
 
281
- def open_font(*args)
282
- write_request(X11::Form::OpenFont.new(*args))
329
+ def list_fonts(...) = write_sync(Form::ListFonts.new(...), Form::ListFontsReply)
330
+ def open_font(...) = write_request(Form::OpenFont.new(...))
331
+ def change_gc(...) = write_request(Form::ChangeGC.new(...))
332
+ def change_save_set(...)= write_request(Form::ChangeSaveSet.new(...))
333
+
334
+ def reparent_window(window, parent, x, y, save: true)
335
+ # You so almost always want this that it should've been a single request
336
+ change_save_set(0, window) if save
337
+ write_request(Form::ReparentWindow.new(window, parent, x,y))
283
338
  end
339
+
340
+ def map_window(...) = write_request(Form::MapWindow.new(...))
341
+ def unmap_window(...) = write_request(Form::UnmapWindow.new(...))
284
342
 
285
- def change_gc(*args)
286
- write_request(X11::Form::ChangeGC.new(*args))
343
+ def u8(*args) = args.pack("c*")
344
+ def u16(*args) = args.pack("v*")
345
+ def u32(*args) = args.pack("V*")
346
+ def atom_enum(val) = open_enum(val, {cardinal: Form::CardinalAtom, atom: Form::AtomAtom, window: Form::WindowAtom})
347
+ def window(*args)
348
+ args.each {|a| raise "Window expected" if a.nil? }
349
+ u32(*args)
287
350
  end
288
351
 
289
- def map_window(*args)
290
- write_request(X11::Form::MapWindow.new(*args))
352
+ def open_enum(val, map) = (map[val].nil? ? val : map[val])
353
+
354
+ def set_input_focus(revert_to, focus, time=:now)
355
+ # FIXME: This is an experiment.
356
+ # Upside: Simpler. Downside: Doesn't work server-side.
357
+ #
358
+ revert_to = open_enum(revert_to, {none: 0, pointer_root: 1, parent: 2})
359
+ focus = open_enum(focus, {none: 0, pointer_root: 1 })
360
+ time = open_enum(time, {current_time: 0, now: 0})
361
+ write_packet(u8(42,revert_to), u16(3), window(focus), u32(time))
291
362
  end
292
363
 
293
364
  def grab_key(owner_events, grab_window, modifiers, keycode, pointer_mode, keyboard_mode)
294
- write_request(X11::Form::GrabKey.new(
365
+ write_request(Form::GrabKey.new(
295
366
  owner_events,
296
367
  grab_window,
297
368
  modifiers,
298
369
  keycode,
299
- pointer_mode == :async ? 1 : 0,
370
+ pointer_mode == :async ? 1 : 0,
300
371
  keyboard_mode == :async ? 1 : 0
301
372
  ))
302
373
  end
303
374
 
304
375
  def grab_button(owner_events, grab_window, event_mask, pointer_mode,
305
376
  keyboard_mode, confine_to, cursor, button, modifiers)
306
- write_request(X11::Form::GrabButton.new(
377
+ write_request(Form::GrabButton.new(
307
378
  owner_events, grab_window, event_mask,
308
379
  pointer_mode == :async ? 1 : 0,
309
380
  keyboard_mode == :async ? 1 : 0,
@@ -311,41 +382,27 @@ module X11
311
382
  )
312
383
  end
313
384
 
385
+ def set_value(values, mask, x)
386
+ if x
387
+ values << x
388
+ mask
389
+ else
390
+ 0
391
+ end
392
+ end
393
+
314
394
  def configure_window(window, x: nil, y: nil, width: nil, height: nil,
315
395
  border_width: nil, sibling: nil, stack_mode: nil)
316
396
 
317
397
  mask = 0
318
398
  values = []
319
399
 
320
- if x
321
- mask |= 0x001
322
- values << x
323
- end
324
-
325
- if y
326
- mask |= 0x002
327
- values << y
328
- end
329
-
330
- if width
331
- mask |= 0x004
332
- values << width
333
- end
334
-
335
- if height
336
- mask |= 0x008
337
- values << height
338
- end
339
-
340
- if border_width
341
- mask |= 0x010
342
- values << border_width
343
- end
344
-
345
- if sibling
346
- mask |= 0x020
347
- values << sibling
348
- end
400
+ mask |= set_value(values, 0x001, x)
401
+ mask |= set_value(values, 0x002, y)
402
+ mask |= set_value(values, 0x004, width)
403
+ mask |= set_value(values, 0x008, height)
404
+ mask |= set_value(values, 0x010, border_width)
405
+ mask |= set_value(values, 0x020, sibling)
349
406
 
350
407
  if stack_mode
351
408
  mask |= 0x040
@@ -354,7 +411,7 @@ module X11
354
411
  when :below then 1
355
412
  when :top_if then 2
356
413
  when :bottom_if then 3
357
- when :opposite then 4
414
+ when :opposite then 4
358
415
  else raise "Unknown stack_mode #{stack_mode.inspect}"
359
416
  end
360
417
  end
@@ -369,49 +426,26 @@ module X11
369
426
  # FIXME:
370
427
  # The rest can be found here:
371
428
  # https://tronche.com/gui/x/xlib/GC/manipulating.html#XGCValues
372
- if foreground
373
- mask |= 0x04
374
- args << foreground
375
- end
376
- if background
377
- mask |= 0x08
378
- args << background
379
- end
380
-
429
+ mask |= set_value(args, 0x04, foreground)
430
+ mask |= set_value(args, 0x08, background)
381
431
 
382
432
  gc = new_id
383
433
  write_request(X11::Form::CreateGC.new(gc, window, mask, args))
384
434
  gc
385
435
  end
386
436
 
387
- def put_image(*args)
388
- write_request(X11::Form::PutImage.new(*args))
389
- end
390
-
391
- def clear_area(*args)
392
- write_request(X11::Form::ClearArea.new(*args))
393
- end
394
-
395
- def copy_area(*args)
396
- write_request(X11::Form::CopyArea.new(*args))
397
- end
398
-
399
- def image_text8(*args)
400
- write_request(X11::Form::ImageText8.new(*args))
401
- end
402
-
403
- def image_text16(*args)
404
- write_request(X11::Form::ImageText16.new(*args))
405
- end
406
-
407
- def poly_fill_rectangle(*args)
408
- write_request(X11::Form::PolyFillRectangle.new(*args))
437
+ def put_image(*args) = write_request(X11::Form::PutImage.new(*args))
438
+ def clear_area(*args) = write_request(X11::Form::ClearArea.new(*args))
439
+ def copy_area(*args) = write_request(X11::Form::CopyArea.new(*args))
440
+ def image_text8(*args) = write_request(X11::Form::ImageText8.new(*args))
441
+ def image_text16(*args)= write_request(X11::Form::ImageText16.new(*args))
442
+ def poly_fill_rectangle(wid, gc, *rects)
443
+ rects = rects.map{|r| r.is_a?(Array) ? Form::Rectangle.new(*r) : r}
444
+ write_request(X11::Form::PolyFillRectangle.new(wid, gc, rects))
409
445
  end
410
446
 
411
447
  def create_pixmap(depth, drawable, w,h)
412
- pid = new_id
413
- write_request(X11::Form::CreatePixmap.new(depth, pid, drawable, w,h))
414
- pid
448
+ new_id.tap{|pid| write_request(Form::CreatePixmap.new(depth, pid, drawable, w,h)) }
415
449
  end
416
450
 
417
451
  # XRender
@@ -437,8 +471,8 @@ module X11
437
471
 
438
472
  def render_query_pict_formats
439
473
  @render_formats ||= write_sync(
440
- X11::Form::XRenderQueryPictFormats.new(render_opcode),
441
- X11::Form::XRenderQueryPictFormatsReply
474
+ Form::XRenderQueryPictFormats.new(render_opcode),
475
+ Form::XRenderQueryPictFormatsReply
442
476
  )
443
477
  end
444
478
 
@@ -459,26 +493,26 @@ module X11
459
493
  case sym
460
494
  when :a8
461
495
  @a8 ||= formats.formats.find do |f|
462
- f.type == 1 &&
496
+ f.type == 1 &&
463
497
  f.depth == 8 &&
464
498
  f.direct.alpha_mask == 255
465
499
  end
466
500
  when :rgb24
467
501
  @rgb24 ||= formats.formats.find do |f|
468
- f.type == 1 &&
469
- f.depth == 24 &&
470
- f.direct.red == 16 &&
502
+ f.type == 1 &&
503
+ f.depth == 24 &&
504
+ f.direct.red == 16 &&
471
505
  f.direct.green == 8 &&
472
- f.direct.blue == 0
506
+ f.direct.blue == 0
473
507
  end
474
508
  when :argb24
475
509
  @argb24 ||= formats.formats.find do |f|
476
- f.type == 1 &&
477
- f.depth == 32 &&
510
+ f.type == 1 &&
511
+ f.depth == 32 &&
478
512
  f.direct.alpha == 24 &&
479
- f.direct.red == 16 &&
513
+ f.direct.red == 16 &&
480
514
  f.direct.green == 8 &&
481
- f.direct.blue == 0
515
+ f.direct.blue == 0
482
516
  end
483
517
  else
484
518
  raise "Unsupported format (a4/a1 by omission)"
data/lib/X11/form.rb CHANGED
@@ -65,13 +65,6 @@ module X11
65
65
 
66
66
  if value.is_a?(BaseForm)
67
67
  v = value.to_packet
68
- elsif value.is_a?(Symbol)
69
- #if !@atoms[value]
70
- # reply = write_sync(X11::Forms::InternAtom.new(false, value.to_s), X11::Forms::InternAtomReply)
71
- # @
72
- #end
73
- #value = @atoms[value]
74
- raise "FIXME"
75
68
  else
76
69
  #p [s,value]
77
70
  v = s.type_klass.pack(value)
@@ -81,14 +74,14 @@ module X11
81
74
  when :unused
82
75
  sz = s.size.respond_to?(:call) ? s.size.call(self) : s.size
83
76
  "\x00" * sz
84
- when :length
77
+ when :length, :format_length
85
78
  #p [s,value]
86
79
  #p [value.size]
87
80
  s.type_klass.pack(value.size)
88
81
  when :string
89
82
  s.type_klass.pack(value)
90
83
  when :list
91
- value.collect do |obj|
84
+ Array(value).collect do |obj|
92
85
  if obj.is_a?(BaseForm)
93
86
  obj.to_packet
94
87
  else
@@ -127,8 +120,17 @@ module X11
127
120
  when :length
128
121
  size = s.type_klass.unpack( socket.read(s.type_klass.size) )
129
122
  lengths[s.name] = size
123
+ when :format_length
124
+ size = s.type_klass.unpack( socket.read(s.type_klass.size) )
125
+ lengths[s.name] = case form.format
126
+ when 8 then size
127
+ when 16 then size*2
128
+ when 32 then size*4
129
+ else 0
130
+ end
130
131
  when :string
131
- val = s.type_klass.unpack(socket, lengths[s.name])
132
+ len = lengths[s.name]
133
+ val = s.type_klass.unpack(socket, len)
132
134
  form.instance_variable_set("@#{s.name}", val)
133
135
  when :list
134
136
  len = lengths[s.name]
@@ -177,12 +179,14 @@ module X11
177
179
  end
178
180
 
179
181
  def fields
180
- super+Array(@structs).dup.delete_if{|s| s.type == :unused or s.type == :length }
182
+ super+Array(@structs).dup.delete_if{|s| s.type == :unused or s.type == :length or s.type == :format_length}
181
183
  end
182
184
  end
183
185
  end
184
186
 
187
+ AtomAtom=4
185
188
  CardinalAtom=6
189
+ WindowAtom=33
186
190
 
187
191
  ##
188
192
  ## X11 Packet Defintions
@@ -247,9 +251,9 @@ module X11
247
251
  end
248
252
 
249
253
  class DisplayInfo < BaseForm
250
- field :release_number, Uint32
251
- field :resource_id_base, Uint32
252
- field :resource_id_mask, Uint32
254
+ field :release_number, Uint32
255
+ field :resource_id_base, Uint32
256
+ field :resource_id_mask, Uint32
253
257
  field :motion_buffer_size, Uint32
254
258
  field :vendor, Uint16, :length
255
259
  field :maximum_request_length, Uint16
@@ -258,11 +262,11 @@ module X11
258
262
  field :image_byte_order, Signifigance
259
263
  field :bitmap_bit_order, Signifigance
260
264
  field :bitmap_format_scanline_unit, Uint8
261
- field :bitmap_format_scanline_pad, Uint8
265
+ field :bitmap_format_scanline_pad, Uint8
262
266
  field :min_keycode, KeyCode
263
267
  field :max_keycode, KeyCode
264
268
  unused 4
265
- field :vendor, String8, :string
269
+ field :vendor, String8, :string
266
270
  field :formats, FormatInfo, :list
267
271
  field :screens, ScreenInfo, :list
268
272
  end
@@ -287,13 +291,13 @@ module X11
287
291
  # XRender structures
288
292
 
289
293
  class DirectFormat < BaseForm
290
- field :red, Uint16
291
- field :red_mask, Uint16
292
- field :green, Uint16
294
+ field :red, Uint16
295
+ field :red_mask, Uint16
296
+ field :green, Uint16
293
297
  field :green_mask, Uint16
294
- field :blue, Uint16
295
- field :blue_mask, Uint16
296
- field :alpha, Uint16
298
+ field :blue, Uint16
299
+ field :blue_mask, Uint16
300
+ field :alpha, Uint16
297
301
  field :alpha_mask, Uint16
298
302
  end
299
303
 
@@ -328,8 +332,8 @@ module X11
328
332
  # Requests
329
333
 
330
334
  CopyFromParent = 0
331
- InputOutput = 1
332
- InputOnly = 2
335
+ InputOutput = 1
336
+ InputOnly = 2
333
337
 
334
338
  CWBackPixmap = 0x0001
335
339
  CWBackPixel = 0x0002
@@ -337,23 +341,29 @@ module X11
337
341
  CWBorderPixel = 0x0008
338
342
  CWBitGravity = 0x0010
339
343
  CWWinGravity = 0x0020
340
- CWBackingStore= 0x0040
341
- CWSaveUnder = 0x0400
342
- CWEventMask = 0x0800
343
- CWColorMap = 0x2000
344
-
345
- KeyPressMask = 0x00001
346
- KeyReleaseMask = 0x00002
347
- ButtonPressMask = 0x00004
348
- ButtonReleaseMask = 0x00008
349
- EnterWindowMask = 0x00010
350
- LeaveWindowMask = 0x00020
351
- PointerMotionMask = 0x00040
352
- PointerMotionHintMask = 0x00080
353
- Button1MotionMask = 0x00100
354
- ExposureMask = 0x08000
355
- StructureNotifyMask = 0x20000
356
- SubstructureNotifyMask = 0x80000
344
+ CWBackingStore = 0x0040
345
+ CWBackingPlanes = 0x0080
346
+ CWBackingPixel = 0x0100
347
+ CWOverrideRedirect = 0x0200
348
+ CWSaveUnder = 0x0400
349
+ CWEventMask = 0x0800
350
+ CWColorMap = 0x2000
351
+
352
+ KeyPressMask = 0x000001
353
+ KeyReleaseMask = 0x000002
354
+ ButtonPressMask = 0x000004
355
+ ButtonReleaseMask = 0x000008
356
+ EnterWindowMask = 0x000010
357
+ LeaveWindowMask = 0x000020
358
+ PointerMotionMask = 0x000040
359
+ PointerMotionHintMask = 0x000080
360
+ Button1MotionMask = 0x000100
361
+ ExposureMask = 0x008000
362
+ StructureNotifyMask = 0x020000
363
+ SubstructureNotifyMask = 0x080000
364
+ SubstructureRedirectMask=0x100000
365
+ FocusChangeMask = 0x200000
366
+ PropertyChangeMask = 0x400000
357
367
 
358
368
  class CreateWindow < BaseForm
359
369
  field :opcode, Uint8, value: 1
@@ -394,14 +404,14 @@ module X11
394
404
  field :sequence_number, Uint16
395
405
  field :reply_length, Uint32
396
406
  field :visual, VisualID
397
- field :class, Uint16
407
+ field :wclass, Uint16
398
408
  field :bit_gravity, Uint8
399
409
  field :win_gravity, Uint8
400
410
  field :backing_planes, Uint32
401
411
  field :backing_pixel, Uint32
402
412
  field :save_under, Bool
403
413
  field :map_is_installed, Bool
404
- field :map_state, Bool
414
+ field :map_state, Uint8
405
415
  field :override_redirect, Bool
406
416
  field :colormap, Colormap
407
417
  field :all_event_masks, Uint32
@@ -417,6 +427,23 @@ module X11
417
427
  field :window, Window
418
428
  end
419
429
 
430
+ class ChangeSaveSet < BaseForm
431
+ field :opcode, Uint8, value: 6
432
+ field :mode, Uint8
433
+ field :request_length, Uint16, value: 2
434
+ field :window, Window
435
+ end
436
+
437
+ class ReparentWindow < BaseForm
438
+ field :opcode, Uint8, value: 7
439
+ unused 1
440
+ field :request_length, Uint16, value: 4
441
+ field :window, Window
442
+ field :parent, Window
443
+ field :x, Int16
444
+ field :y, Int16
445
+ end
446
+
420
447
  class MapWindow < BaseForm
421
448
  field :opcode, Uint8, value: 8
422
449
  unused 1
@@ -424,6 +451,13 @@ module X11
424
451
  field :window, Window
425
452
  end
426
453
 
454
+ class UnmapWindow < BaseForm
455
+ field :opcode, Uint8, value: 10
456
+ unused 1
457
+ field :request_length, Uint16, value: 2
458
+ field :window, Window
459
+ end
460
+
427
461
  class ConfigureWindow < BaseForm
428
462
  field :opcode, Uint8, value: 12
429
463
  unused 1
@@ -455,6 +489,25 @@ module X11
455
489
  unused 10
456
490
  end
457
491
 
492
+ class QueryTree < BaseForm
493
+ field :opcode, Uint8, value: 15
494
+ unused 1
495
+ field :request_length, Uint16, value: 2
496
+ field :window, Window
497
+ end
498
+
499
+ class QueryTreeReply < BaseForm
500
+ field :reply, Uint8, value: 1
501
+ unused 1
502
+ field :sequence_number, Uint16
503
+ field :reply_length, Uint32
504
+ field :root, Window
505
+ field :parent, Window
506
+ field :children, Uint16, :length
507
+ unused 14
508
+ field :children, Window, :list
509
+ end
510
+
458
511
  class InternAtom < BaseForm
459
512
  field :opcode, Uint8, value: 16
460
513
  field :only_if_exists, Bool
@@ -480,6 +533,22 @@ module X11
480
533
  unused 20
481
534
  end
482
535
 
536
+ class GetAtomName < BaseForm
537
+ field :opcode, Uint8, value: 17
538
+ unused 1
539
+ field :request_length, Uint16, value: 2
540
+ field :atom, Atom
541
+ end
542
+
543
+ class AtomName < Reply
544
+ unused 1
545
+ field :sequence_number, Uint16
546
+ field :reply_length, Uint32
547
+ field :name, Uint16, :length
548
+ unused 22
549
+ field :name, String8, :string
550
+ end
551
+
483
552
  Replace = 0
484
553
  Prepend = 1
485
554
  Append = 2
@@ -496,12 +565,33 @@ module X11
496
565
  field :type, Atom
497
566
  field :format, Uint8
498
567
  unused 3
499
- field :data, Uint32, value: ->(cp) {
500
- cp.data.length / 4
501
- }
568
+ field :data, Uint32, value: ->(cp) { cp.data.length / (cp.format/8) }
502
569
  field :data, Uint8, :list
503
570
  end
504
571
 
572
+ class GetProperty < BaseForm
573
+ field :opcode, Uint8, value: 20
574
+ field :delete, Bool
575
+ field :request_length, Uint16, value: 6
576
+ field :window, Window
577
+ field :property, Atom
578
+ field :type, Atom
579
+ field :long_offset, Uint32
580
+ field :long_length, Uint32
581
+ end
582
+
583
+ class Property < BaseForm
584
+ field :reply, Uint8, value: 1
585
+ field :format, Uint8
586
+ field :sequence_number, Uint16
587
+ field :reply_length, Uint32
588
+ field :type, Atom
589
+ field :bytes_after, Uint32
590
+ field :value, Uint32, :format_length
591
+ unused 12
592
+ field :value, String8, :string
593
+ end
594
+
505
595
  class GrabButton < BaseForm
506
596
  field :opcode, Uint8, value: 28
507
597
  field :owner_events, Bool
@@ -528,6 +618,18 @@ module X11
528
618
  field :keyboard_mode, Uint8
529
619
  unused 3
530
620
  end
621
+
622
+ class OpenFont < BaseForm
623
+ field :opcode, Uint8, value: 45
624
+ unused 1
625
+ field :request_length, Uint16, value: ->(of) {
626
+ 3+(of.name.length+3)/4
627
+ }
628
+ field :fid, Font
629
+ field :name, Uint16, :length
630
+ unused 2
631
+ field :name, String8, :string
632
+ end
531
633
 
532
634
  class ListFonts < BaseForm
533
635
  field :opcode, Uint8, value: 49
@@ -618,11 +720,11 @@ module X11
618
720
  field :src_drawable, Drawable
619
721
  field :dst_drawable, Drawable
620
722
  field :gc, Gcontext
621
- field :src_x, Uint16
622
- field :src_y, Uint16
623
- field :dst_x, Uint16
624
- field :dst_y, Uint16
625
- field :width, Uint16
723
+ field :src_x, Uint16
724
+ field :src_y, Uint16
725
+ field :dst_x, Uint16
726
+ field :dst_y, Uint16
727
+ field :width, Uint16
626
728
  field :height, Uint16
627
729
  end
628
730
 
@@ -754,7 +856,7 @@ module X11
754
856
  field :sequence_number, Uint16
755
857
  end
756
858
 
757
- class PressEvent < SimpleEvent
859
+ class InputEvent < SimpleEvent
758
860
  field :time, Uint32
759
861
  field :root, Window
760
862
  field :event, Window
@@ -764,6 +866,32 @@ module X11
764
866
  field :event_x, Int16
765
867
  field :event_y, Int16
766
868
  field :state, Uint16
869
+ end
870
+
871
+ class EnterLeaveNotify < InputEvent
872
+ field :mode, Uint8
873
+ field :same_screen_or_focus, Uint8
874
+
875
+ def same_screen = same_screen_or_focus.anybit?(0x02)
876
+ def focus = same_screen_or_focus.anybit?(0x01)
877
+ end
878
+
879
+ class EnterNotify < EnterLeaveNotify
880
+ end
881
+
882
+ class LeaveNotify < EnterLeaveNotify
883
+ end
884
+
885
+ class FocusIn < SimpleEvent
886
+ field :event, Window
887
+ field :mode, Uint8
888
+ unused 23
889
+ end
890
+
891
+ class FocusOut < FocusIn
892
+ end
893
+
894
+ class PressEvent < InputEvent
767
895
  field :same_screen, Bool
768
896
  unused 1
769
897
  end
@@ -782,6 +910,31 @@ module X11
782
910
 
783
911
  class ButtonRelease < PressEvent
784
912
  end
913
+
914
+ class ReparentNotify < SimpleEvent
915
+ field :event, Window
916
+ field :window, Window
917
+ field :parent, Window
918
+ field :x, Int16
919
+ field :y, Int16
920
+ field :override_redirect, Bool
921
+ unused 11
922
+ end
923
+
924
+ class ConfigureRequest < Event # 23
925
+ field :stack_mode, Uint8
926
+ field :sequence_number, Uint16
927
+ field :parent, Window
928
+ field :window, Window
929
+ field :sibling, Window
930
+ field :x, Int16
931
+ field :y, Int16
932
+ field :width, Uint16
933
+ field :height, Uint16
934
+ field :border_width, Uint16
935
+ field :value_mask, Uint16
936
+ unused 4
937
+ end
785
938
 
786
939
  class Expose < SimpleEvent
787
940
  field :window, Window
@@ -800,14 +953,51 @@ module X11
800
953
  unused 21
801
954
  end
802
955
 
956
+ class CreateNotify < SimpleEvent # 16
957
+ field :parent, Window
958
+ field :window, Window
959
+ field :x, Int16
960
+ field :y, Int16
961
+ field :width, Uint16
962
+ field :height, Uint16
963
+ field :border_width, Uint16
964
+ field :override_redirect, Bool
965
+ end
966
+
967
+ class DestroyNotify < Event
968
+ unused 1
969
+ field :sequence_number, Uint16
970
+ field :event, Window
971
+ field :window, Window
972
+ unused 20
973
+ end
974
+
975
+ class UnmapNotify < Event
976
+ unused 1
977
+ field :sequence_number, Uint16
978
+ field :event, Window
979
+ field :window, Window
980
+ field :from_configure, Bool
981
+ unused 19
982
+ end
983
+
803
984
  class MapNotify < Event
804
985
  unused 1
805
986
  field :sequence_number, Uint16
806
987
  field :event, Window
988
+ field :window, Window
807
989
  field :override_redirect, Bool
808
990
  unused 19
809
991
  end
810
992
 
993
+ class MapRequest < Event
994
+ unused 1
995
+ field :sequence_number, Uint16
996
+ field :parent, Window
997
+ field :window, Window
998
+ unused 20
999
+ end
1000
+
811
1001
  class ConfigureNotify < Event
812
1002
  unused 1
813
1003
  field :sequence_number, Uint16
@@ -822,6 +1012,24 @@ module X11
822
1012
  unused 5
823
1013
  end
824
1014
 
1015
+ class ClientMessage < Event
1016
+ field :format, Uint8
1017
+ field :sequence_number, Uint16
1018
+ field :window, Window
1019
+ field :type, Atom
1020
+ field :data, X11::Type::Message
1021
+ end
1022
+
1023
+ class PropertyNotify < Event # 28
1024
+ unused 1
1025
+ field :sequence_number, Uint16
1026
+ field :window, Window
1027
+ field :atom, Atom
1028
+ field :time, Uint32
1029
+ field :state, Uint8
1030
+ unused 15
1031
+ end
1032
+
825
1033
 
826
1034
  # XRender extension
827
1035
  # From https://cgit.freedesktop.org/xorg/proto/renderproto/tree/renderproto.h
data/lib/X11/type.rb CHANGED
@@ -1,51 +1,54 @@
1
1
  # This module is used for encoding Ruby Objects to binary
2
2
  # data. The types Int8, Int16, etc. are data-types defined
3
- # in the X11 protocol. We wrap each data-type in a lambda expression
4
- # which gets evaluated when a packet is created.
3
+ # in the X11 protocol.
5
4
 
6
5
  module X11
7
6
  module Type
8
7
 
9
- def self.define(type, directive, bytesize)
10
- eval %{
11
- class X11::Type::#{type}
12
- def self.pack(x)
13
- [x].pack(\"#{directive}\")
14
- end
15
-
16
- def self.unpack(x)
17
- x.unpack(\"#{directive}\").first
18
- end
19
-
20
- def self.size
21
- #{bytesize}
22
- end
8
+ class BaseType
9
+ @directive = nil
10
+ @bytesize = nil
23
11
 
24
- def self.from_packet(sock)
25
- r = sock.read(size)
26
- r ? unpack(r) : nil
12
+ def self.config(d,b) = (@directive, @bytesize = d,b)
13
+
14
+ def self.pack(x)
15
+ if x.is_a?(Symbol)
16
+ if (t = X11::Form.const_get(x)) && t.is_a?(Numeric)
17
+ x = t
27
18
  end
28
19
  end
29
- }
30
- end
20
+ [x].pack(@directive)
21
+ rescue TypeError => e
22
+ raise "Expected #{self.name}, got #{x.class} (value: #{x})"
23
+ end
31
24
 
25
+ def self.unpack(x) = x.nil? ? nil : x.unpack1(@directive)
26
+ def self.size = @bytesize
27
+ def self.from_packet(sock) = unpack(sock.read(size))
28
+ end
29
+
32
30
  # Primitive Types
33
- define "Int8", "c", 1
34
- define "Int16", "s", 2
35
- define "Int32", "l", 4
36
- define "Uint8", "C", 1
37
- define "Uint16", "S", 2
38
- define "Uint32", "L", 4
31
+ class Int8 < BaseType; config("c",1); end
32
+ class Int16 < BaseType; config("s",2); end
33
+ class Int32 < BaseType; config("l",4); end
34
+ class Uint8 < BaseType; config("C",1); end
35
+ class Uint16 < BaseType; config("S",2); end
36
+ class Uint32 < BaseType; config("L",4); end
37
+
38
+ class Message
39
+ def self.pack(x) = x.b
40
+ def self.unpack(x) = x.b
41
+ def self.size = 20
42
+ def self.from_packet(sock) = sock.read(2).b
43
+ end
39
44
 
40
45
  class String8
41
46
  def self.pack(x)
42
- x.force_encoding("ASCII-8BIT") + "\x00"*(-x.length & 3)
47
+ x.b + "\x00"*(-x.length & 3)
43
48
  end
44
49
 
45
-
46
-
47
-
48
50
  def self.unpack(socket, size)
51
+ raise "Expected size for String8" if size.nil?
49
52
  val = socket.read(size)
50
53
  unused_padding = (4 - (size % 4)) % 4
51
54
  socket.read(unused_padding)
@@ -55,7 +58,7 @@ module X11
55
58
 
56
59
  class String16
57
60
  def self.pack(x)
58
- x.encode("UTF-16BE").force_encoding("ASCII-8BIT") + "\x00\x00"*(-x.length & 1)
61
+ x.encode("UTF-16BE").b + "\x00\x00"*(-x.length & 1)
59
62
  end
60
63
 
61
64
  def self.unpack(socket, size)
@@ -68,28 +71,14 @@ module X11
68
71
 
69
72
 
70
73
  class String8Unpadded
71
- def self.pack(x)
72
- x
73
- end
74
-
75
-
76
- def self.unpack(socket, size)
77
- val = socket.read(size)
78
- end
74
+ def self.pack(x) = x
75
+ def self.unpack(socket, size) = socket.read(size)
79
76
  end
80
-
77
+
81
78
  class Bool
82
- def self.pack(x)
83
- x ? "\x01" : "\x00"
84
- end
85
-
86
- def self.unpack(str)
87
- str[0] == "\x01"
88
- end
89
-
90
- def self.size
91
- 1
92
- end
79
+ def self.pack(x) = (x ? "\x01" : "\x00")
80
+ def self.unpack(str) = (str[0] == "\x01")
81
+ def self.size = 1
93
82
  end
94
83
 
95
84
  KeyCode = Uint8
data/lib/X11/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module X11
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.6"
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.4
4
+ version: 0.0.6
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-11-21 00:00:00.000000000 Z
12
+ date: 2023-12-28 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Pure Ruby X11 bindings
15
15
  email: