pure-x11 0.0.7 → 0.0.11
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 +4 -4
- data/CLAUDE.md +47 -0
- data/Gemfile.lock +1 -1
- data/README.md +10 -0
- data/example/test.rb +24 -23
- data/lib/X11/display.rb +21 -5
- data/lib/X11/form.rb +26 -12
- data/lib/X11/version.rb +1 -1
- data/lib/X11/window.rb +39 -0
- data/lib/X11.rb +2 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0aef4dac032e7cc033a474d8b3f19920c2dd18e55a98cdf08329c0dcb9f360e
|
4
|
+
data.tar.gz: 346955046f31e2e53a61183ddcd9d19db11dab82c9de8b9ea04c92b9f4900e93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 417b477de5a70c6e0e568e218f007544823e1986c7969bd666bf4a8c9382c2af349ac745c693f3b9fe07aeccc9119fadda5daa6b0dfad6bb388218dc6af2ba03
|
7
|
+
data.tar.gz: 153aacfb1fa54955eb14d6b186a65868a803f486c88d55b483a55097b81d545fab3888ebaff3332c1fa0d964d71293a49a08654d6fef71ed7501ab6926028185
|
data/CLAUDE.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Ruby X11 Development Guidelines
|
2
|
+
|
3
|
+
## Build Commands
|
4
|
+
- Install dependencies: `bundle install`
|
5
|
+
- Run all tests: `rake test`
|
6
|
+
- Run single test: `ruby test/specific_test.rb`
|
7
|
+
|
8
|
+
## Code Style
|
9
|
+
- Indentation: 2 spaces
|
10
|
+
- Naming: snake_case for methods/variables, CamelCase for classes
|
11
|
+
- Constants: ALL_CAPS or CamelCase (matching X11 protocol names)
|
12
|
+
- Methods: One-line with `=` for simple methods (Ruby 3 syntax)
|
13
|
+
- Error handling: Custom X11 error hierarchy (X11::BasicError, etc.)
|
14
|
+
- Imports: require_relative for internal files, require for gems
|
15
|
+
|
16
|
+
## Organization
|
17
|
+
- Core functionality in lib/X11.rb
|
18
|
+
- Components in lib/X11/ directory
|
19
|
+
- Protocol definitions using DSL in form.rb
|
20
|
+
- Test files in test/ directory with _test.rb suffix
|
21
|
+
|
22
|
+
## Testing
|
23
|
+
- Uses Minitest::Spec syntax: `_(object).must_equal expected`
|
24
|
+
- Tests require helper.rb which sets up the environment
|
25
|
+
- Mock objects for testing sockets/connections
|
26
|
+
|
27
|
+
## Documentation
|
28
|
+
- Comments for complex logic
|
29
|
+
- Reference X11 protocol documentation when implementing specs
|
30
|
+
|
31
|
+
## Adding X11 Protocol Requests
|
32
|
+
1. Define request form in lib/X11/form.rb:
|
33
|
+
```ruby
|
34
|
+
class XRenderFreePicture < BaseForm
|
35
|
+
field :req_type, Uint8
|
36
|
+
field :render_req_type, Uint8, value: 7
|
37
|
+
field :request_length, Uint16, value: 2
|
38
|
+
field :picture, Uint32
|
39
|
+
end
|
40
|
+
```
|
41
|
+
2. Add helper method in lib/X11/display.rb:
|
42
|
+
```ruby
|
43
|
+
def render_free_picture(picture)
|
44
|
+
write_request(Form::XRenderFreePicture.new(render_opcode, picture))
|
45
|
+
end
|
46
|
+
```
|
47
|
+
3. Update X11::VERSION in lib/X11/version.rb after adding new functionality
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -9,6 +9,16 @@ upstread everything.
|
|
9
9
|
This library is based off of Mathieu Bouchard's work on his RubyX11 project,
|
10
10
|
and Richard Ramsdens excellent start on Ruby-X11.
|
11
11
|
|
12
|
+
Current known use (all mine...):
|
13
|
+
|
14
|
+
* [RubyWM](https://github.com/vidarh/rubywm) - Pure Ruby window manager
|
15
|
+
* [Skrift-X11](https://github.com/vidarh/skrift-x11) - X11 integration for pure Ruby Truetype font rendering
|
16
|
+
* Rebar - not yet published wm toolbar
|
17
|
+
* RubyTerm (name TBD) - not yet published version of Ruby terminal
|
18
|
+
|
19
|
+
If you're thinking of using pure-x11, drop me a note and I'll start being more
|
20
|
+
cautious about breaking changes ;)
|
21
|
+
|
12
22
|
Contributors
|
13
23
|
------------
|
14
24
|
|
data/example/test.rb
CHANGED
@@ -14,7 +14,7 @@ dpy = display = X11::Display.new
|
|
14
14
|
screen = dpy.screens.first
|
15
15
|
root = screen.root
|
16
16
|
|
17
|
-
|
17
|
+
window = X11::Window.create(dpy,
|
18
18
|
0, 0, # x,y
|
19
19
|
1000, 600, # w,h
|
20
20
|
# FIXME: WTH isn't depth: 32 working here?
|
@@ -32,17 +32,18 @@ wid = dpy.create_window(
|
|
32
32
|
#dpy.next_packet
|
33
33
|
#exit(0)
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
|
36
|
+
def set_window_opacity(window, opacity)
|
37
|
+
window.change_property(
|
37
38
|
:replace,
|
38
|
-
|
39
|
+
"_NET_WM_WINDOW_OPACITY",
|
39
40
|
:cardinal, 32,
|
40
41
|
[(0xffffffff * opacity).to_i].pack("V").unpack("C*")
|
41
42
|
)
|
42
43
|
end
|
43
44
|
|
44
45
|
|
45
|
-
set_window_opacity(
|
46
|
+
set_window_opacity(window, 0.8)
|
46
47
|
|
47
48
|
#p dpy.display_info
|
48
49
|
|
@@ -87,11 +88,11 @@ def lookup_keysym(dpy, event)
|
|
87
88
|
end
|
88
89
|
|
89
90
|
puts "Mapping"
|
90
|
-
|
91
|
+
window.map
|
91
92
|
|
92
|
-
$gc = gc =
|
93
|
-
$gc2 =
|
94
|
-
$gc3 =
|
93
|
+
$gc = gc = window.create_gc(foreground: 0xff0000)
|
94
|
+
$gc2 = window.create_gc(foreground: 0xffffff, background: 0x444444)
|
95
|
+
$gc3 = window.create_gc
|
95
96
|
|
96
97
|
|
97
98
|
puts "Main loop"
|
@@ -123,7 +124,7 @@ $sft = SFT.new($f)
|
|
123
124
|
$sft.x_scale = 15
|
124
125
|
$sft.y_scale = 15
|
125
126
|
$glyphcache = {}
|
126
|
-
def render_glyph(
|
127
|
+
def render_glyph(window, x,y, ch)
|
127
128
|
gid = $sft.lookup(ch.ord)
|
128
129
|
mtx = $sft.gmetrics(gid)
|
129
130
|
data = $glyphcache[gid]
|
@@ -135,45 +136,45 @@ def render_glyph(display, wid, x,y, ch)
|
|
135
136
|
# p img
|
136
137
|
data = img.pixels.map {|px|
|
137
138
|
"\0\0"+px.chr+"\0" #+ "\0\0\0"
|
138
|
-
}.join.
|
139
|
+
}.join.b
|
139
140
|
$glyphcache[gid] = data
|
140
141
|
end
|
141
142
|
depth = 24
|
142
143
|
# p data
|
143
144
|
#p img
|
144
145
|
# p ch
|
145
|
-
|
146
|
-
:ZPixmap,
|
146
|
+
window.put_image(
|
147
|
+
:ZPixmap, $gc2,
|
147
148
|
mtx.min_width,mtx.min_height,
|
148
149
|
x, y - mtx.y_offset, 0, depth, data
|
149
150
|
)
|
150
151
|
mtx.advance_width
|
151
152
|
end
|
152
153
|
|
153
|
-
def render_str(
|
154
|
+
def render_str(window, x,y, str)
|
154
155
|
str.each_byte do |ch|
|
155
|
-
off = render_glyph(
|
156
|
+
off = render_glyph(window, x, y, ch.chr)
|
156
157
|
x+= off
|
157
158
|
end
|
158
159
|
end
|
159
160
|
|
160
|
-
def redraw(
|
161
|
-
|
162
|
-
|
163
|
-
|
161
|
+
def redraw(window, gc)
|
162
|
+
window.poly_fill_rectangle(gc, [20,20, 60, 80])
|
163
|
+
window.clear_area(false, 30, 30, 5, 5)
|
164
|
+
window.image_text16($gc2, 30, 70, "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ")
|
164
165
|
#"\u25f0\u25ef Hello World")
|
165
|
-
|
166
|
-
:ZPixmap,
|
166
|
+
window.put_image(
|
167
|
+
:ZPixmap, $gc2,
|
167
168
|
$png.width, $png.height, 80, 120, 0, 24, $data
|
168
169
|
)
|
169
|
-
render_str(
|
170
|
+
render_str(window, 30,90, 'HelloWorld')
|
170
171
|
end
|
171
172
|
|
172
173
|
loop do
|
173
174
|
pkt = display.next_packet
|
174
175
|
if pkt
|
175
176
|
p pkt
|
176
|
-
redraw(
|
177
|
+
redraw(window, gc) if pkt.is_a?(X11::Form::Expose)
|
177
178
|
|
178
179
|
if pkt.is_a?(X11::Form::KeyPress)
|
179
180
|
lookup_keysym(dpy,pkt)
|
data/lib/X11/display.rb
CHANGED
@@ -3,10 +3,16 @@ require 'stringio'
|
|
3
3
|
|
4
4
|
module X11
|
5
5
|
|
6
|
-
class DisplayError <
|
7
|
-
class ConnectionError <
|
8
|
-
class AuthorizationError <
|
9
|
-
class ProtocolError <
|
6
|
+
class DisplayError < X11::BasicError; end
|
7
|
+
class ConnectionError < X11::BasicError; end
|
8
|
+
class AuthorizationError < X11::BasicError; end
|
9
|
+
class ProtocolError < X11::BasicError; end
|
10
|
+
class Error < X11::BasicError
|
11
|
+
def initialize(pkt)
|
12
|
+
super("Error: #{pkt.error}, code=#{pkt.code}, seq=#{pkt.sequence_number}, resource=#{pkt.bad_resource_id}, major=#{pkt.major_opcode}, minor=#{pkt.minor_opcode}")
|
13
|
+
@error = pkt
|
14
|
+
end
|
15
|
+
end
|
10
16
|
|
11
17
|
class Display
|
12
18
|
attr_accessor :socket
|
@@ -189,7 +195,7 @@ module X11
|
|
189
195
|
STDERR.puts "write_sync_req: #{ob.inspect}" if @debug
|
190
196
|
pkt = q.shift
|
191
197
|
STDERR.puts "write_sync_rep: #{pkt.inspect}" if @debug
|
192
|
-
raise(pkt) if pkt.is_a?(X11::Form::Error)
|
198
|
+
raise(X11::Error.new(pkt)) if pkt.is_a?(X11::Form::Error)
|
193
199
|
return pkt if !pkt.is_a?(String)
|
194
200
|
reply ? reply.from_packet(StringIO.new(pkt)) : pkt
|
195
201
|
end
|
@@ -520,6 +526,8 @@ module X11
|
|
520
526
|
send_event(propagate, destination, mask, event)
|
521
527
|
end
|
522
528
|
|
529
|
+
def query_tree(...) = write_sync(X11::Form::QueryTree.new(...), X11::Form::QueryTreeReply)
|
530
|
+
|
523
531
|
def put_image(*args) = write_request(X11::Form::PutImage.new(*args))
|
524
532
|
def clear_area(*args) = write_request(X11::Form::ClearArea.new(*args))
|
525
533
|
def copy_area(*args) = write_request(X11::Form::CopyArea.new(*args))
|
@@ -533,6 +541,10 @@ module X11
|
|
533
541
|
def create_pixmap(depth, drawable, w,h)
|
534
542
|
new_id.tap{|pid| write_request(Form::CreatePixmap.new(depth, pid, drawable, w,h)) }
|
535
543
|
end
|
544
|
+
|
545
|
+
def free_pixmap(pixmap)
|
546
|
+
write_request(Form::FreePixmap.new(pixmap))
|
547
|
+
end
|
536
548
|
|
537
549
|
# XRender
|
538
550
|
|
@@ -643,6 +655,10 @@ module X11
|
|
643
655
|
write_request(Form::XRenderCreateSolidFill.new(render_opcode,fill,color))
|
644
656
|
fill
|
645
657
|
end
|
658
|
+
|
659
|
+
def render_free_picture(picture)
|
660
|
+
write_request(Form::XRenderFreePicture.new(render_opcode, picture))
|
661
|
+
end
|
646
662
|
|
647
663
|
private
|
648
664
|
|
data/lib/X11/form.rb
CHANGED
@@ -694,6 +694,13 @@ module X11
|
|
694
694
|
field :width, Uint16
|
695
695
|
field :height, Uint16
|
696
696
|
end
|
697
|
+
|
698
|
+
class FreePixmap < BaseForm
|
699
|
+
field :opcode, Uint8, value: 54
|
700
|
+
unused 1
|
701
|
+
field :request_length, Uint16, value: 2
|
702
|
+
field :pixmap, Pixmap
|
703
|
+
end
|
697
704
|
|
698
705
|
class Str < BaseForm
|
699
706
|
field :name, Uint8, :length, value: ->(str) { str.name.length }
|
@@ -875,18 +882,18 @@ module X11
|
|
875
882
|
# FIXME: Events have quite a bit of redundancy, but unfortunately
|
876
883
|
# BaseForm can't handle subclassing well.
|
877
884
|
|
878
|
-
Shift
|
879
|
-
Lock
|
880
|
-
Control =
|
881
|
-
Mod1
|
882
|
-
Mod2
|
883
|
-
Mod3
|
884
|
-
Mod4
|
885
|
-
Mod5
|
886
|
-
Button1 =
|
887
|
-
Button2 =
|
888
|
-
Button3 =
|
889
|
-
Button4 =
|
885
|
+
Shift = 0x0001
|
886
|
+
Lock = 0x0002
|
887
|
+
Control = 0x0004
|
888
|
+
Mod1 = 0x0008
|
889
|
+
Mod2 = 0x0010
|
890
|
+
Mod3 = 0x0020
|
891
|
+
Mod4 = 0x0040
|
892
|
+
Mod5 = 0x0080
|
893
|
+
Button1 = 0x0100
|
894
|
+
Button2 = 0x0200
|
895
|
+
Button3 = 0x0400
|
896
|
+
Button4 = 0x0800
|
890
897
|
Button5 = 0x1000
|
891
898
|
|
892
899
|
class Event < BaseForm
|
@@ -1217,5 +1224,12 @@ module X11
|
|
1217
1224
|
field :fill, Uint32
|
1218
1225
|
field :color, XRenderColor
|
1219
1226
|
end
|
1227
|
+
|
1228
|
+
class XRenderFreePicture < BaseForm
|
1229
|
+
field :req_type, Uint8
|
1230
|
+
field :render_req_type, Uint8, value: 7
|
1231
|
+
field :request_length, Uint16, value: 2
|
1232
|
+
field :picture, Uint32
|
1233
|
+
end
|
1220
1234
|
end
|
1221
1235
|
end
|
data/lib/X11/version.rb
CHANGED
data/lib/X11/window.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
module X11
|
3
|
+
|
4
|
+
# A simple helper class that makes requests where the
|
5
|
+
# target object is a specific window a bit more convenient
|
6
|
+
class Window
|
7
|
+
attr_reader :dpy, :wid
|
8
|
+
|
9
|
+
def initialize(dpy,wid)
|
10
|
+
@dpy, @wid = dpy,wid
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.create(dpy, ...)
|
14
|
+
wid = dpy.create_window(...)
|
15
|
+
Window.new(dpy,wid)
|
16
|
+
end
|
17
|
+
|
18
|
+
def query_tree = dpy.query_tree(@wid)
|
19
|
+
def map = dpy.map_window(@wid)
|
20
|
+
def unmap = dpy.unmap_window(@wid)
|
21
|
+
def destroy = dpy.destroy_window(@wid)
|
22
|
+
def get_geometry = dpy.get_geometry(@wid)
|
23
|
+
def configure(...) = dpy.configure_window(@wid, ...)
|
24
|
+
def get_property(...) = dpy.get_property(@wid,...)
|
25
|
+
def grab_key(arg, ...) = dpy.grab_key(arg, @wid, ...)
|
26
|
+
def grab_button(arg,...) = dpy.grab_button(arg, @wid, ...)
|
27
|
+
def change_property(mode, ...) = dpy.change_property(mode, @wid, ...)
|
28
|
+
def set_input_focus(mode) = dpy.set_input_focus(mode, @wid)
|
29
|
+
def select_input(...) = dpy.select_input(@wid,...)
|
30
|
+
def get_window_attributes(...) = dpy.get_window_attributes(@wid,...)
|
31
|
+
def change_attributes(...) = dpy.change_window_attributes(@wid,...)
|
32
|
+
|
33
|
+
def image_text16(...) = dpy.image_text16(@wid, ...)
|
34
|
+
def clear_area(arg, ...) = dpy.clear_area(arg, @wid, ...)
|
35
|
+
def poly_fill_rectangle(...) = dpy.poly_fill_rectangle(@wid, ...)
|
36
|
+
def put_image(type, ...) = dpy.put_image(type, @wid, ...)
|
37
|
+
def create_gc(...) = dpy.create_gc(@wid, ...)
|
38
|
+
end
|
39
|
+
end
|
data/lib/X11.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module X11
|
2
|
-
class
|
2
|
+
class BasicError < StandardError; end
|
3
3
|
end
|
4
4
|
|
5
5
|
require 'socket'
|
@@ -9,4 +9,5 @@ require_relative './X11/display'
|
|
9
9
|
require_relative './X11/screen'
|
10
10
|
require_relative './X11/type'
|
11
11
|
require_relative './X11/form'
|
12
|
+
require_relative './X11/window'
|
12
13
|
require_relative './X11/keysyms'
|
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
|
+
version: 0.0.11
|
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:
|
12
|
+
date: 2025-03-25 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Pure Ruby X11 bindings
|
15
15
|
email:
|
@@ -19,6 +19,7 @@ extensions: []
|
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
21
|
- ".gitignore"
|
22
|
+
- CLAUDE.md
|
22
23
|
- Gemfile
|
23
24
|
- Gemfile.lock
|
24
25
|
- LICENSE.txt
|
@@ -38,6 +39,7 @@ files:
|
|
38
39
|
- lib/X11/screen.rb
|
39
40
|
- lib/X11/type.rb
|
40
41
|
- lib/X11/version.rb
|
42
|
+
- lib/X11/window.rb
|
41
43
|
- ruby-x11.gemspec
|
42
44
|
- test/core_test.rb
|
43
45
|
- test/form_test.rb
|