rbgl 0.1.0 → 1.0.1
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +20 -2
- data/README.md +130 -74
- data/Rakefile +7 -0
- data/bench/renderer_bench.rb +283 -0
- data/docs/.nojekyll +1 -0
- data/docs/index.html +38 -0
- data/examples/array_test.rb +1 -1
- data/examples/color_test.rb +1 -1
- data/examples/cube_spinning.rb +1 -1
- data/examples/gradient.rb +1 -1
- data/examples/multi_return_test.rb +1 -1
- data/examples/plasma.rb +1 -1
- data/examples/sphere_raymarch.rb +1 -1
- data/examples/triangle_window.rb +1 -1
- data/exe/rbgl +42 -0
- data/lib/rbgl/cli/doctor.rb +155 -0
- data/lib/rbgl/engine/buffer.rb +150 -40
- data/lib/rbgl/engine/clip_space_clipper.rb +163 -0
- data/lib/rbgl/engine/context.rb +133 -63
- data/lib/rbgl/engine/framebuffer.rb +153 -48
- data/lib/rbgl/engine/immutable_color.rb +32 -0
- data/lib/rbgl/engine/pipeline.rb +38 -7
- data/lib/rbgl/engine/rasterizer/attribute_interpolator.rb +195 -0
- data/lib/rbgl/engine/rasterizer/line_renderer.rb +88 -0
- data/lib/rbgl/engine/rasterizer/point_renderer.rb +35 -0
- data/lib/rbgl/engine/rasterizer/triangle_renderer.rb +136 -0
- data/lib/rbgl/engine/rasterizer.rb +65 -171
- data/lib/rbgl/engine/shader/base_shader.rb +51 -0
- data/lib/rbgl/engine/shader/builtins.rb +257 -0
- data/lib/rbgl/engine/shader/dynamic_data.rb +73 -0
- data/lib/rbgl/engine/shader.rb +5 -318
- data/lib/rbgl/engine/texture.rb +264 -51
- data/lib/rbgl/engine.rb +4 -1
- data/lib/rbgl/gui/backend.rb +21 -34
- data/lib/rbgl/gui/backend_factory.rb +89 -0
- data/lib/rbgl/gui/cocoa/backend.rb +59 -46
- data/lib/rbgl/gui/cocoa/key_mapper.rb +48 -0
- data/lib/rbgl/gui/event.rb +4 -2
- data/lib/rbgl/gui/file_backend/bmp_writer.rb +63 -0
- data/lib/rbgl/gui/file_backend/frame_writer.rb +35 -0
- data/lib/rbgl/gui/file_backend/png_writer.rb +18 -0
- data/lib/rbgl/gui/file_backend/ppm_writer.rb +26 -0
- data/lib/rbgl/gui/file_backend.rb +50 -55
- data/lib/rbgl/gui/wayland/backend.rb +214 -60
- data/lib/rbgl/gui/wayland/codec.rb +50 -0
- data/lib/rbgl/gui/wayland/connection.rb +188 -231
- data/lib/rbgl/gui/wayland/event_dispatcher.rb +165 -0
- data/lib/rbgl/gui/wayland/global_binder.rb +46 -0
- data/lib/rbgl/gui/wayland/input_mapper.rb +61 -0
- data/lib/rbgl/gui/wayland/protocol_objects/arguments.rb +63 -0
- data/lib/rbgl/gui/wayland/protocol_objects/display.rb +54 -0
- data/lib/rbgl/gui/wayland/protocol_objects/seat.rb +115 -0
- data/lib/rbgl/gui/wayland/protocol_objects/shm.rb +157 -0
- data/lib/rbgl/gui/wayland/protocol_objects/surface.rb +33 -0
- data/lib/rbgl/gui/wayland/protocol_objects/xdg_shell.rb +60 -0
- data/lib/rbgl/gui/wayland/protocol_objects.rb +8 -0
- data/lib/rbgl/gui/window/event_dispatcher.rb +30 -0
- data/lib/rbgl/gui/window/render_loop.rb +111 -0
- data/lib/rbgl/gui/window.rb +74 -84
- data/lib/rbgl/gui/x11/atom_cache.rb +29 -0
- data/lib/rbgl/gui/x11/backend.rb +73 -49
- data/lib/rbgl/gui/x11/connection.rb +284 -219
- data/lib/rbgl/gui/x11/event_parser.rb +71 -0
- data/lib/rbgl/gui/x11/key_mapper.rb +48 -0
- data/lib/rbgl/gui/x11/pixel_encoder.rb +164 -0
- data/lib/rbgl/gui/x11/request_encoder.rb +155 -0
- data/lib/rbgl/gui/x11/setup_parser.rb +138 -0
- data/lib/rbgl/gui/x11/transport.rb +81 -0
- data/lib/rbgl/gui/x11/x_authority.rb +107 -0
- data/lib/rbgl/gui.rb +3 -5
- data/lib/rbgl/version.rb +1 -1
- metadata +63 -24
- data/examples/chemical_heartbeat.rb +0 -166
- data/examples/dark_transit.rb +0 -166
- data/examples/fractured_orb.rb +0 -428
- data/examples/fractured_orb_rb.rb +0 -598
- data/examples/hexagonal_flow.rb +0 -333
- data/examples/teapot.rb +0 -362
- data/examples/teapot_mcu.rb +0 -344
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../backend"
|
|
4
|
+
|
|
5
|
+
module RBGL
|
|
6
|
+
module GUI
|
|
7
|
+
module Wayland
|
|
8
|
+
class GlobalBinder
|
|
9
|
+
BINDINGS = {
|
|
10
|
+
"wl_compositor" => [:compositor, Compositor, 4],
|
|
11
|
+
"wl_shm" => [:shm, Shm, 1],
|
|
12
|
+
"xdg_wm_base" => [:xdg_wm_base, XdgWmBase, 2],
|
|
13
|
+
"wl_seat" => [:seat, Seat, 5]
|
|
14
|
+
}.freeze
|
|
15
|
+
REQUIRED_INTERFACES = %w[wl_compositor wl_shm xdg_wm_base].freeze
|
|
16
|
+
|
|
17
|
+
def initialize(connection)
|
|
18
|
+
@connection = connection
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def bind!(registry, globals)
|
|
22
|
+
validate_required_globals!(globals)
|
|
23
|
+
|
|
24
|
+
BINDINGS.each_with_object({}) do |(interface, binding), bound|
|
|
25
|
+
slot, klass, max_version = binding
|
|
26
|
+
global = globals[interface]
|
|
27
|
+
next unless global
|
|
28
|
+
|
|
29
|
+
version = [global[:version], max_version].min
|
|
30
|
+
object_id = registry.bind(global[:name], interface, version)
|
|
31
|
+
bound[slot] = @connection.register_object(klass.new(@connection, object_id, version: version))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def validate_required_globals!(globals)
|
|
38
|
+
missing = REQUIRED_INTERFACES - globals.keys
|
|
39
|
+
return if missing.empty?
|
|
40
|
+
|
|
41
|
+
raise GUI::BackendUnavailable, "Wayland globals missing: #{missing.join(', ')}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBGL
|
|
4
|
+
module GUI
|
|
5
|
+
module Wayland
|
|
6
|
+
module InputMapper
|
|
7
|
+
KEY_NAMES = {
|
|
8
|
+
1 => :escape,
|
|
9
|
+
14 => :backspace,
|
|
10
|
+
15 => :tab,
|
|
11
|
+
28 => :enter,
|
|
12
|
+
29 => :left_control,
|
|
13
|
+
42 => :left_shift,
|
|
14
|
+
54 => :right_shift,
|
|
15
|
+
56 => :left_alt,
|
|
16
|
+
57 => :space,
|
|
17
|
+
58 => :caps_lock,
|
|
18
|
+
87 => :f11,
|
|
19
|
+
88 => :f12,
|
|
20
|
+
97 => :right_control,
|
|
21
|
+
100 => :right_alt,
|
|
22
|
+
102 => :home,
|
|
23
|
+
103 => :up,
|
|
24
|
+
104 => :page_up,
|
|
25
|
+
105 => :left,
|
|
26
|
+
106 => :right,
|
|
27
|
+
107 => :end,
|
|
28
|
+
108 => :down,
|
|
29
|
+
109 => :page_down,
|
|
30
|
+
110 => :insert,
|
|
31
|
+
111 => :delete,
|
|
32
|
+
125 => :left_meta,
|
|
33
|
+
126 => :right_meta
|
|
34
|
+
}.merge(
|
|
35
|
+
(2..10).zip(%i[one two three four five six seven eight nine]).to_h,
|
|
36
|
+
{ 11 => :zero },
|
|
37
|
+
(16..25).zip(%i[q w e r t y u i o p]).to_h,
|
|
38
|
+
(30..38).zip(%i[a s d f g h j k l]).to_h,
|
|
39
|
+
(44..50).zip(%i[z x c v b n m]).to_h,
|
|
40
|
+
(59..68).zip(%i[f1 f2 f3 f4 f5 f6 f7 f8 f9 f10]).to_h
|
|
41
|
+
).freeze
|
|
42
|
+
|
|
43
|
+
POINTER_BUTTONS = {
|
|
44
|
+
0x110 => 1,
|
|
45
|
+
0x111 => 3,
|
|
46
|
+
0x112 => 2
|
|
47
|
+
}.freeze
|
|
48
|
+
|
|
49
|
+
module_function
|
|
50
|
+
|
|
51
|
+
def key(code)
|
|
52
|
+
KEY_NAMES.fetch(code, code)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def button(code)
|
|
56
|
+
POINTER_BUTTONS.fetch(code, code)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBGL
|
|
4
|
+
module GUI
|
|
5
|
+
module Wayland
|
|
6
|
+
TypedArgument = Struct.new(:type, :value)
|
|
7
|
+
|
|
8
|
+
module Arguments
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def uint(value)
|
|
12
|
+
TypedArgument.new(:uint, Integer(value))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def int(value)
|
|
16
|
+
TypedArgument.new(:int, Integer(value))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def fixed(value)
|
|
20
|
+
TypedArgument.new(:fixed, Float(value))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def string(value)
|
|
24
|
+
TypedArgument.new(:string, value.to_s)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def object(value)
|
|
28
|
+
object_id = value.respond_to?(:id) ? value.id : value
|
|
29
|
+
TypedArgument.new(:object, Integer(object_id))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def new_id(value)
|
|
33
|
+
TypedArgument.new(:new_id, Integer(value))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class WaylandObject
|
|
38
|
+
attr_reader :id, :connection, :version
|
|
39
|
+
|
|
40
|
+
def initialize(connection, id, version: 1)
|
|
41
|
+
@connection = connection
|
|
42
|
+
@id = id
|
|
43
|
+
@version = version
|
|
44
|
+
@destroyed = false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def send_request(opcode, *args)
|
|
48
|
+
@connection.send_request(@id, opcode, *args)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def release(opcode, since: 1)
|
|
54
|
+
return if @destroyed
|
|
55
|
+
|
|
56
|
+
send_request(opcode) if @version >= since
|
|
57
|
+
@connection.unregister_object(@id) if @connection.respond_to?(:unregister_object)
|
|
58
|
+
@destroyed = true
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBGL
|
|
4
|
+
module GUI
|
|
5
|
+
module Wayland
|
|
6
|
+
class Display < WaylandObject
|
|
7
|
+
def initialize(connection)
|
|
8
|
+
super(connection, 1)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def sync
|
|
12
|
+
callback_id = @connection.allocate_id
|
|
13
|
+
send_request(0, Arguments.new_id(callback_id))
|
|
14
|
+
@connection.register_object(Callback.new(@connection, callback_id))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def get_registry
|
|
18
|
+
registry_id = @connection.allocate_id
|
|
19
|
+
send_request(1, Arguments.new_id(registry_id))
|
|
20
|
+
@connection.register_object(Registry.new(@connection, registry_id))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Registry < WaylandObject
|
|
25
|
+
def bind(name, interface, version)
|
|
26
|
+
new_id = @connection.allocate_id
|
|
27
|
+
send_request(
|
|
28
|
+
0,
|
|
29
|
+
Arguments.uint(name),
|
|
30
|
+
Arguments.string(interface),
|
|
31
|
+
Arguments.uint(version),
|
|
32
|
+
Arguments.new_id(new_id)
|
|
33
|
+
)
|
|
34
|
+
new_id
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class Callback < WaylandObject
|
|
39
|
+
def initialize(connection, id)
|
|
40
|
+
super
|
|
41
|
+
@done = false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def done?
|
|
45
|
+
@done
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def handle_done
|
|
49
|
+
@done = true
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBGL
|
|
4
|
+
module GUI
|
|
5
|
+
module Wayland
|
|
6
|
+
class Seat < WaylandObject
|
|
7
|
+
POINTER_CAPABILITY = 1
|
|
8
|
+
KEYBOARD_CAPABILITY = 2
|
|
9
|
+
|
|
10
|
+
attr_reader :keyboard, :pointer
|
|
11
|
+
|
|
12
|
+
def handle_capabilities(capabilities)
|
|
13
|
+
update_pointer(capabilities & POINTER_CAPABILITY != 0)
|
|
14
|
+
update_keyboard(capabilities & KEYBOARD_CAPABILITY != 0)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def destroy
|
|
18
|
+
@pointer&.destroy
|
|
19
|
+
@keyboard&.destroy
|
|
20
|
+
release(3, since: 5)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def update_pointer(available)
|
|
26
|
+
@pointer ||= create_pointer if available
|
|
27
|
+
return if available || !@pointer
|
|
28
|
+
|
|
29
|
+
@pointer.destroy
|
|
30
|
+
@pointer = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def update_keyboard(available)
|
|
34
|
+
@keyboard ||= create_keyboard if available
|
|
35
|
+
return if available || !@keyboard
|
|
36
|
+
|
|
37
|
+
@keyboard.destroy
|
|
38
|
+
@keyboard = nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def create_pointer
|
|
42
|
+
object_id = @connection.allocate_id
|
|
43
|
+
send_request(0, Arguments.new_id(object_id))
|
|
44
|
+
@connection.register_object(Pointer.new(@connection, object_id, version: @version))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def create_keyboard
|
|
48
|
+
object_id = @connection.allocate_id
|
|
49
|
+
send_request(1, Arguments.new_id(object_id))
|
|
50
|
+
@connection.register_object(Keyboard.new(@connection, object_id, version: @version))
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class Keyboard < WaylandObject
|
|
55
|
+
attr_reader :focused_surface_id, :keymap, :keymap_format, :modifiers
|
|
56
|
+
|
|
57
|
+
def initialize(...)
|
|
58
|
+
super
|
|
59
|
+
@modifiers = {}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def focus(surface_id)
|
|
63
|
+
@focused_surface_id = surface_id
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def blur
|
|
67
|
+
@focused_surface_id = nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def handle_keymap(format, size, io)
|
|
71
|
+
raise GUI::BackendUnavailable, "Wayland keymap event did not include a file descriptor" unless io
|
|
72
|
+
|
|
73
|
+
@keymap_format = { 0 => :none, 1 => :xkb_v1 }.fetch(format, format)
|
|
74
|
+
@keymap = io.read(size)&.delete_suffix("\x00")
|
|
75
|
+
ensure
|
|
76
|
+
io&.close
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def handle_modifiers(depressed:, latched:, locked:, group:)
|
|
80
|
+
@modifiers = {
|
|
81
|
+
depressed: depressed,
|
|
82
|
+
latched: latched,
|
|
83
|
+
locked: locked,
|
|
84
|
+
group: group
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def destroy
|
|
89
|
+
release(0, since: 3)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class Pointer < WaylandObject
|
|
94
|
+
attr_reader :focused_surface_id, :x, :y
|
|
95
|
+
|
|
96
|
+
def focus(surface_id)
|
|
97
|
+
@focused_surface_id = surface_id
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def blur
|
|
101
|
+
@focused_surface_id = nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def move(x, y)
|
|
105
|
+
@x = x
|
|
106
|
+
@y = y
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def destroy
|
|
110
|
+
release(1, since: 3)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBGL
|
|
4
|
+
module GUI
|
|
5
|
+
module Wayland
|
|
6
|
+
class Shm < WaylandObject
|
|
7
|
+
def create_pool(file, size)
|
|
8
|
+
pool_id = @connection.allocate_id
|
|
9
|
+
@connection.send_request_with_fd(@id, 0, Arguments.new_id(pool_id), Arguments.int(size), file)
|
|
10
|
+
@connection.register_object(ShmPool.new(@connection, pool_id))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class ShmPool < WaylandObject
|
|
15
|
+
def create_buffer(offset, width, height, stride, format)
|
|
16
|
+
buffer_id = @connection.allocate_id
|
|
17
|
+
format_val = case format
|
|
18
|
+
when :argb8888 then 0
|
|
19
|
+
when :xrgb8888 then 1
|
|
20
|
+
else
|
|
21
|
+
raise ArgumentError, "Unsupported Wayland SHM format: #{format}"
|
|
22
|
+
end
|
|
23
|
+
send_request(
|
|
24
|
+
0,
|
|
25
|
+
Arguments.new_id(buffer_id),
|
|
26
|
+
Arguments.int(offset),
|
|
27
|
+
Arguments.int(width),
|
|
28
|
+
Arguments.int(height),
|
|
29
|
+
Arguments.int(stride),
|
|
30
|
+
Arguments.uint(format_val)
|
|
31
|
+
)
|
|
32
|
+
@connection.register_object(WlBuffer.new(@connection, buffer_id))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def destroy
|
|
36
|
+
send_request(1)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class WlBuffer < WaylandObject
|
|
41
|
+
def initialize(connection, id)
|
|
42
|
+
super
|
|
43
|
+
@busy = false
|
|
44
|
+
@destroy_requested = false
|
|
45
|
+
@destroyed = false
|
|
46
|
+
@release_callbacks = []
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def on_release(&block)
|
|
50
|
+
@release_callbacks << block if block
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def mark_in_use
|
|
54
|
+
@busy = true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def available?
|
|
58
|
+
!@busy && !@destroy_requested && !@destroyed
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def busy?
|
|
62
|
+
@busy
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def handle_release
|
|
66
|
+
@busy = false
|
|
67
|
+
@release_callbacks.each(&:call)
|
|
68
|
+
finalize_destroy if @destroy_requested
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def destroy(force: false)
|
|
72
|
+
return if @destroyed || (@destroy_requested && !force)
|
|
73
|
+
|
|
74
|
+
if @busy && !force
|
|
75
|
+
@destroy_requested = true
|
|
76
|
+
else
|
|
77
|
+
finalize_destroy
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def finalize_destroy
|
|
84
|
+
return if @destroyed
|
|
85
|
+
|
|
86
|
+
send_request(0)
|
|
87
|
+
@destroyed = true
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class ShmBuffer
|
|
92
|
+
attr_reader :wl_buffer
|
|
93
|
+
|
|
94
|
+
def initialize(file, pool, wl_buffer)
|
|
95
|
+
@file = file
|
|
96
|
+
@pool = pool
|
|
97
|
+
@wl_buffer = wl_buffer
|
|
98
|
+
@destroy_requested = false
|
|
99
|
+
@destroyed = false
|
|
100
|
+
@file.binmode
|
|
101
|
+
@file.seek(0)
|
|
102
|
+
@wl_buffer.on_release { handle_release }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def write(data)
|
|
106
|
+
@file.seek(0)
|
|
107
|
+
@file.write(data)
|
|
108
|
+
@file.flush
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def available?
|
|
112
|
+
@wl_buffer.available?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def mark_in_use
|
|
116
|
+
@wl_buffer.mark_in_use
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def id
|
|
120
|
+
@wl_buffer.id
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def destroy(force: false)
|
|
124
|
+
return if @destroyed
|
|
125
|
+
|
|
126
|
+
@destroy_requested = true
|
|
127
|
+
begin
|
|
128
|
+
force ? @wl_buffer.destroy(force: true) : @wl_buffer.destroy
|
|
129
|
+
ensure
|
|
130
|
+
finalize_destroy if force || !@wl_buffer.busy?
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def destroyed?
|
|
135
|
+
@destroyed
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
def handle_release
|
|
141
|
+
finalize_destroy if @destroy_requested
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def finalize_destroy
|
|
145
|
+
return if @destroyed
|
|
146
|
+
|
|
147
|
+
begin
|
|
148
|
+
@pool.destroy
|
|
149
|
+
ensure
|
|
150
|
+
@file.close unless @file.closed?
|
|
151
|
+
@destroyed = true
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBGL
|
|
4
|
+
module GUI
|
|
5
|
+
module Wayland
|
|
6
|
+
class Compositor < WaylandObject
|
|
7
|
+
def create_surface
|
|
8
|
+
surface_id = @connection.allocate_id
|
|
9
|
+
send_request(0, Arguments.new_id(surface_id))
|
|
10
|
+
@connection.register_object(Surface.new(@connection, surface_id))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Surface < WaylandObject
|
|
15
|
+
def attach(buffer, x, y)
|
|
16
|
+
send_request(1, Arguments.object(buffer), Arguments.int(x), Arguments.int(y))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def damage(x, y, width, height)
|
|
20
|
+
send_request(2, Arguments.int(x), Arguments.int(y), Arguments.int(width), Arguments.int(height))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def commit
|
|
24
|
+
send_request(6)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def destroy
|
|
28
|
+
send_request(0)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBGL
|
|
4
|
+
module GUI
|
|
5
|
+
module Wayland
|
|
6
|
+
class XdgWmBase < WaylandObject
|
|
7
|
+
def get_xdg_surface(surface)
|
|
8
|
+
xdg_surface_id = @connection.allocate_id
|
|
9
|
+
send_request(2, Arguments.new_id(xdg_surface_id), Arguments.object(surface))
|
|
10
|
+
@connection.register_object(XdgSurface.new(@connection, xdg_surface_id))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def pong(serial)
|
|
14
|
+
send_request(3, Arguments.uint(serial))
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class XdgSurface < WaylandObject
|
|
19
|
+
def initialize(connection, id)
|
|
20
|
+
super
|
|
21
|
+
@configured = false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def configured?
|
|
25
|
+
@configured
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def get_toplevel
|
|
29
|
+
toplevel_id = @connection.allocate_id
|
|
30
|
+
send_request(1, Arguments.new_id(toplevel_id))
|
|
31
|
+
@connection.register_object(XdgToplevel.new(@connection, toplevel_id))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def ack_configure(serial)
|
|
35
|
+
send_request(4, Arguments.uint(serial))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def handle_configure(serial)
|
|
39
|
+
ack_configure(serial)
|
|
40
|
+
@connection.flush
|
|
41
|
+
@configured = true
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def destroy
|
|
45
|
+
send_request(0)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class XdgToplevel < WaylandObject
|
|
50
|
+
def set_title(title)
|
|
51
|
+
send_request(2, Arguments.string(title))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def destroy
|
|
55
|
+
send_request(0)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "protocol_objects/arguments"
|
|
4
|
+
require_relative "protocol_objects/display"
|
|
5
|
+
require_relative "protocol_objects/surface"
|
|
6
|
+
require_relative "protocol_objects/shm"
|
|
7
|
+
require_relative "protocol_objects/seat"
|
|
8
|
+
require_relative "protocol_objects/xdg_shell"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBGL
|
|
4
|
+
module GUI
|
|
5
|
+
class Window
|
|
6
|
+
class EventDispatcher
|
|
7
|
+
def initialize(backend:, event_handlers:, on_resize:)
|
|
8
|
+
@backend = backend
|
|
9
|
+
@event_handlers = event_handlers
|
|
10
|
+
@on_resize = on_resize
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def process
|
|
14
|
+
Array(poll_events).each do |event|
|
|
15
|
+
next unless event.is_a?(Event)
|
|
16
|
+
|
|
17
|
+
@on_resize.call(event) if event.type == :resize
|
|
18
|
+
@event_handlers[event.type].each { |handler| handler.call(event) }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def poll_events
|
|
25
|
+
@backend.poll_events
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|