qt 0.1.6 → 0.1.8
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/ext/qt_ruby_bridge/runtime_signals.cpp +27 -1
- data/lib/qt/event_runtime.rb +64 -12
- data/lib/qt/event_runtime_dispatch.rb +10 -3
- data/lib/qt/generated_setter_aliases_runtime.rb +37 -0
- data/lib/qt/generated_singleton_forwarders_runtime.rb +24 -0
- data/lib/qt/object_list_codec.rb +23 -0
- data/lib/qt/object_wrapper.rb +106 -7
- data/lib/qt/version.rb +1 -1
- data/lib/qt.rb +6 -1
- data/scripts/generate_bridge/auto_methods.rb +3 -1
- data/scripts/generate_bridge/cpp_method_return_emitter.rb +12 -0
- data/scripts/generate_bridge/ffi_api.rb +2 -0
- data/scripts/generate_bridge/spec_discovery.rb +32 -6
- data/scripts/generate_bridge.rb +97 -16
- metadata +5 -3
- data/lib/qt/children_tracking.rb +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5b47b66563f703c260222b8ac0e38f2bf27e4ee654dd3152181bb8866e93e182
|
|
4
|
+
data.tar.gz: 797218dab7d7ce473510b05bd500c8151503b0ebc018648c5d82a5e5abb7e8f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 37e94ba0242411ddd9f46d6858f397f53e2d2d62e38ba7ccba9a15fc517f86291b015d82dd359dfe0eb5ce12a011ebeb379d95a23c607c1be299883d5c24ed2a
|
|
7
|
+
data.tar.gz: 5fc3cc069da9615f8efb690d2888f5ec7f5c02422885e070331b4e271381405a082993c705d100c9e30b6ceb5661471701769c81e5ff6ff072024fe34c7b9c15
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include "qt_ruby_runtime.hpp"
|
|
2
2
|
|
|
3
3
|
#include <QByteArray>
|
|
4
|
+
#include <QCoreApplication>
|
|
4
5
|
#include <QDateTimeEdit>
|
|
5
6
|
#include <QMetaMethod>
|
|
6
7
|
#include <QObject>
|
|
@@ -29,6 +30,11 @@ std::unordered_map<QObject*, SignalHandlersByIndex>& signal_handlers() {
|
|
|
29
30
|
return handlers;
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
QObject* signal_callback_context() {
|
|
34
|
+
static QObject fallback_context;
|
|
35
|
+
return QCoreApplication::instance() ? static_cast<QObject*>(QCoreApplication::instance()) : &fallback_context;
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
int resolve_signal_index(QObject* obj, const char* signal_name) {
|
|
33
39
|
if (!obj || !signal_name) {
|
|
34
40
|
return -1;
|
|
@@ -122,7 +128,25 @@ int QtRubyRuntime::qobject_connect_signal(void* object_handle, const char* signa
|
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
const QMetaMethod signal_method = obj->metaObject()->method(signal_index);
|
|
125
|
-
|
|
131
|
+
if (signal_method.name() == "destroyed") {
|
|
132
|
+
QMetaObject::Connection direct_connection =
|
|
133
|
+
QObject::connect(obj, &QObject::destroyed, signal_callback_context(), [obj, signal_index](QObject*) {
|
|
134
|
+
if (!signal_callback_ref()) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
signal_callback_ref()(obj, signal_index, signal_payload_for(obj, signal_index));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (!direct_connection) {
|
|
141
|
+
return -4;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
auto& by_index = signal_handlers()[obj];
|
|
145
|
+
by_index[signal_index].push_back(SignalHandler{signal_index, direct_connection, {}, nullptr});
|
|
146
|
+
return signal_index;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
auto* mapper = new QSignalMapper(QCoreApplication::instance());
|
|
126
150
|
mapper->setMapping(obj, signal_index);
|
|
127
151
|
|
|
128
152
|
const int map_slot_index = mapper->metaObject()->indexOfSlot("map()");
|
|
@@ -146,6 +170,8 @@ int QtRubyRuntime::qobject_connect_signal(void* object_handle, const char* signa
|
|
|
146
170
|
signal_callback_ref()(obj, mapped_signal_index, signal_payload_for(obj, mapped_signal_index));
|
|
147
171
|
});
|
|
148
172
|
|
|
173
|
+
QObject::connect(obj, &QObject::destroyed, mapper, [mapper]() { mapper->deleteLater(); });
|
|
174
|
+
|
|
149
175
|
if (!mapped_connection) {
|
|
150
176
|
QObject::disconnect(signal_connection);
|
|
151
177
|
mapper->deleteLater();
|
data/lib/qt/event_runtime.rb
CHANGED
|
@@ -30,22 +30,30 @@ module Qt
|
|
|
30
30
|
ensure_signal_callback!
|
|
31
31
|
|
|
32
32
|
handle = widget_handle(widget) || raise(ArgumentError, 'widget handle is required')
|
|
33
|
-
per_signal = prepare_signal_registration(handle, signal_name)
|
|
33
|
+
per_signal = prepare_signal_registration(@signal_handlers ||= {}, handle, signal_name)
|
|
34
34
|
per_signal[:blocks] << block
|
|
35
35
|
true
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def
|
|
38
|
+
def on_internal_signal(widget, signal_name, &block)
|
|
39
|
+
raise ArgumentError, 'pass block to on_internal_signal' unless block
|
|
40
|
+
|
|
41
|
+
ensure_native_bridge_ready!
|
|
42
|
+
ensure_signal_callback!
|
|
43
|
+
|
|
44
|
+
handle = widget_handle(widget) || raise(ArgumentError, 'widget handle is required')
|
|
45
|
+
per_signal = prepare_signal_registration(@internal_signal_handlers ||= {}, handle, signal_name)
|
|
46
|
+
per_signal[:blocks] << block
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def prepare_signal_registration(signal_store, handle, signal_name)
|
|
39
51
|
signal_key = signal_name.to_s
|
|
40
52
|
raise ArgumentError, 'signal name is required' if signal_key.empty?
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
per_signal = ((@signal_handlers[handle.address] ||= {})[signal_key] ||= { index: nil, blocks: [] })
|
|
54
|
+
per_signal = ((signal_store[handle.address] ||= {})[signal_key] ||= { index: nil, blocks: [] })
|
|
44
55
|
if per_signal[:index].nil?
|
|
45
|
-
index =
|
|
46
|
-
raise ArgumentError, "failed to connect signal #{signal_key.inspect} (code=#{index})" if index.negative?
|
|
47
|
-
|
|
48
|
-
per_signal[:index] = index
|
|
56
|
+
per_signal[:index] = acquire_signal_registration(handle, signal_key)
|
|
49
57
|
end
|
|
50
58
|
per_signal
|
|
51
59
|
end
|
|
@@ -59,9 +67,14 @@ module Qt
|
|
|
59
67
|
return false if per_widget.nil?
|
|
60
68
|
|
|
61
69
|
signal_key = signal_name&.to_s
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
if signal_key
|
|
71
|
+
per_widget.delete(signal_key)
|
|
72
|
+
release_signal_registration(handle, signal_key)
|
|
73
|
+
else
|
|
74
|
+
per_widget.keys.each { |registered_signal| release_signal_registration(handle, registered_signal) }
|
|
75
|
+
per_widget.clear
|
|
76
|
+
end
|
|
77
|
+
@signal_handlers.delete(handle.address) if per_widget.empty?
|
|
65
78
|
true
|
|
66
79
|
end
|
|
67
80
|
|
|
@@ -103,7 +116,9 @@ module Qt
|
|
|
103
116
|
|
|
104
117
|
@signal_callback = FFI::Function.new(:void, %i[pointer int string]) do |object_handle, signal_index, payload|
|
|
105
118
|
normalized_payload = payload.nil? ? nil : Qt::StringCodec.from_qt_text(payload)
|
|
106
|
-
EventRuntimeDispatch.dispatch_signal(
|
|
119
|
+
EventRuntimeDispatch.dispatch_signal(
|
|
120
|
+
@internal_signal_handlers, @signal_handlers, object_handle, signal_index, normalized_payload
|
|
121
|
+
)
|
|
107
122
|
end
|
|
108
123
|
|
|
109
124
|
Qt::Native.set_signal_callback(@signal_callback)
|
|
@@ -141,5 +156,42 @@ module Qt
|
|
|
141
156
|
@event_handlers.delete(handle.address)
|
|
142
157
|
end
|
|
143
158
|
end
|
|
159
|
+
|
|
160
|
+
def acquire_signal_registration(handle, signal_key)
|
|
161
|
+
@signal_registrations ||= {}
|
|
162
|
+
per_widget = (@signal_registrations[handle.address] ||= {})
|
|
163
|
+
registration = (per_widget[signal_key] ||= { index: nil, refcount: 0 })
|
|
164
|
+
if registration[:index].nil?
|
|
165
|
+
index = Qt::Native.qobject_connect_signal(handle, signal_key)
|
|
166
|
+
raise ArgumentError, "failed to connect signal #{signal_key.inspect} (code=#{index})" if index.negative?
|
|
167
|
+
|
|
168
|
+
registration[:index] = index
|
|
169
|
+
end
|
|
170
|
+
registration[:refcount] += 1
|
|
171
|
+
registration[:index]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def release_signal_registration(handle, signal_key)
|
|
175
|
+
return if @signal_registrations.nil?
|
|
176
|
+
|
|
177
|
+
per_widget = @signal_registrations[handle.address]
|
|
178
|
+
return if per_widget.nil?
|
|
179
|
+
|
|
180
|
+
registration = per_widget[signal_key]
|
|
181
|
+
return if registration.nil?
|
|
182
|
+
|
|
183
|
+
registration[:refcount] -= 1
|
|
184
|
+
return if registration[:refcount].positive?
|
|
185
|
+
|
|
186
|
+
Qt::Native.qobject_disconnect_signal(handle, signal_key)
|
|
187
|
+
per_widget.delete(signal_key)
|
|
188
|
+
@signal_registrations.delete(handle.address) if per_widget.empty?
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def clear_signal_registrations_for_address(address)
|
|
192
|
+
@signal_handlers&.delete(address)
|
|
193
|
+
@internal_signal_handlers&.delete(address)
|
|
194
|
+
@signal_registrations&.delete(address)
|
|
195
|
+
end
|
|
144
196
|
end
|
|
145
197
|
end
|
|
@@ -26,8 +26,15 @@ module Qt
|
|
|
26
26
|
EVENT_RESULT_CONTINUE
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def dispatch_signal(signal_handlers, object_handle, signal_index, payload)
|
|
30
|
-
return unless object_handle
|
|
29
|
+
def dispatch_signal(internal_signal_handlers, signal_handlers, object_handle, signal_index, payload)
|
|
30
|
+
return unless object_handle
|
|
31
|
+
|
|
32
|
+
dispatch_signal_store(signal_handlers, object_handle, signal_index, payload)
|
|
33
|
+
dispatch_signal_store(internal_signal_handlers, object_handle, signal_index, payload)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def dispatch_signal_store(signal_handlers, object_handle, signal_index, payload)
|
|
37
|
+
return unless signal_handlers
|
|
31
38
|
|
|
32
39
|
per_widget = signal_handlers[object_handle.address]
|
|
33
40
|
return unless per_widget
|
|
@@ -36,7 +43,7 @@ module Qt
|
|
|
36
43
|
next unless entry[:index] == signal_index
|
|
37
44
|
|
|
38
45
|
typed_payload = Qt::DateTimeCodec.decode_for_signal(signal_name, payload)
|
|
39
|
-
entry[:blocks].each { |handler| handler.call(typed_payload) }
|
|
46
|
+
entry[:blocks].dup.each { |handler| handler.call(typed_payload) }
|
|
40
47
|
end
|
|
41
48
|
end
|
|
42
49
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Qt
|
|
4
|
+
module GeneratedSetterAliasesRuntime
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def apply!(qt_module)
|
|
8
|
+
qt_module.constants(false).each do |const_name|
|
|
9
|
+
klass = qt_module.const_get(const_name, false)
|
|
10
|
+
next unless klass.is_a?(Class)
|
|
11
|
+
|
|
12
|
+
apply_instance_aliases!(klass)
|
|
13
|
+
apply_singleton_aliases!(klass)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def apply_instance_aliases!(klass)
|
|
18
|
+
apply_aliases_to_target!(klass, klass, :QT_API_SETTER_ALIASES)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def apply_singleton_aliases!(klass)
|
|
22
|
+
apply_aliases_to_target!(klass.singleton_class, klass, :QT_API_SINGLETON_SETTER_ALIASES)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def apply_aliases_to_target!(target, owner, constant_name)
|
|
26
|
+
return unless owner.const_defined?(constant_name, false)
|
|
27
|
+
|
|
28
|
+
owner.const_get(constant_name, false).each do |alias_name, setter_name|
|
|
29
|
+
next if target.method_defined?(alias_name) || target.private_method_defined?(alias_name)
|
|
30
|
+
|
|
31
|
+
target.send(:define_method, alias_name) do |value|
|
|
32
|
+
public_send(setter_name, value)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Qt
|
|
4
|
+
module GeneratedSingletonForwardersRuntime
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def apply!(qt_module)
|
|
8
|
+
qt_module.constants(false).each do |const_name|
|
|
9
|
+
klass = qt_module.const_get(const_name, false)
|
|
10
|
+
next unless klass.is_a?(Class)
|
|
11
|
+
next unless klass.const_defined?(:QT_API_SINGLETON_FORWARDERS, false)
|
|
12
|
+
|
|
13
|
+
klass.const_get(:QT_API_SINGLETON_FORWARDERS, false).each do |method_name|
|
|
14
|
+
next if klass.instance_methods(false).include?(method_name.to_sym)
|
|
15
|
+
next if klass.private_instance_methods(false).include?(method_name.to_sym)
|
|
16
|
+
|
|
17
|
+
klass.send(:define_method, method_name) do |*args, &block|
|
|
18
|
+
self.class.public_send(method_name, *args, &block)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Qt
|
|
6
|
+
# Decodes QObjectList bridge payloads into canonical Ruby wrappers.
|
|
7
|
+
module ObjectListCodec
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def decode(payload, expected_qt_class = 'QObject')
|
|
11
|
+
raw = Qt::StringCodec.from_qt_text(payload.to_s)
|
|
12
|
+
return [] if raw.empty?
|
|
13
|
+
|
|
14
|
+
JSON.parse(raw).filter_map do |address|
|
|
15
|
+
next if address.nil? || address.to_s.empty?
|
|
16
|
+
|
|
17
|
+
Qt::ObjectWrapper.wrap(FFI::Pointer.new(Integer(address, 10)), expected_qt_class)
|
|
18
|
+
end
|
|
19
|
+
rescue JSON::ParserError, ArgumentError
|
|
20
|
+
[]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/qt/object_wrapper.rb
CHANGED
|
@@ -5,14 +5,24 @@ module Qt
|
|
|
5
5
|
module ObjectWrapper
|
|
6
6
|
module_function
|
|
7
7
|
|
|
8
|
+
module ConstructorCacheHook
|
|
9
|
+
def initialize(*args, &block)
|
|
10
|
+
super
|
|
11
|
+
Qt::ObjectWrapper.register_wrapper(self)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
8
15
|
def wrap(pointer, expected_qt_class = nil)
|
|
9
16
|
return nil if null_pointer?(pointer)
|
|
10
17
|
return pointer if pointer.respond_to?(:handle)
|
|
11
18
|
|
|
19
|
+
cached = cached_wrapper_for(pointer)
|
|
20
|
+
return cached if cached
|
|
21
|
+
|
|
12
22
|
klass = resolve_wrapper_class(pointer, expected_qt_class) || fallback_wrapper_class(expected_qt_class)
|
|
13
23
|
return pointer unless klass
|
|
14
24
|
|
|
15
|
-
instantiate_wrapper(klass, pointer)
|
|
25
|
+
register_wrapper(instantiate_wrapper(klass, pointer))
|
|
16
26
|
end
|
|
17
27
|
|
|
18
28
|
def null_pointer?(pointer)
|
|
@@ -26,9 +36,10 @@ module Qt
|
|
|
26
36
|
end
|
|
27
37
|
|
|
28
38
|
def candidate_wrapper_classes(expected_qt_class)
|
|
39
|
+
normalized_qt_class = normalize_expected_qt_class(expected_qt_class)
|
|
29
40
|
@candidate_wrapper_classes ||= {}
|
|
30
|
-
@candidate_wrapper_classes[
|
|
31
|
-
base = fallback_wrapper_class(
|
|
41
|
+
@candidate_wrapper_classes[normalized_qt_class] ||= begin
|
|
42
|
+
base = fallback_wrapper_class(normalized_qt_class)
|
|
32
43
|
wrappers = qobject_wrapper_classes
|
|
33
44
|
wrappers = wrappers.select { |klass| klass <= base } if base
|
|
34
45
|
wrappers.sort_by { |klass| -inheritance_depth(klass) }
|
|
@@ -47,23 +58,95 @@ module Qt
|
|
|
47
58
|
end
|
|
48
59
|
|
|
49
60
|
def fallback_wrapper_class(expected_qt_class)
|
|
50
|
-
|
|
61
|
+
normalized_qt_class = normalize_expected_qt_class(expected_qt_class)
|
|
62
|
+
return nil unless normalized_qt_class
|
|
63
|
+
return nil unless Qt.const_defined?(normalized_qt_class, false)
|
|
51
64
|
|
|
52
|
-
klass = Qt.const_get(
|
|
65
|
+
klass = Qt.const_get(normalized_qt_class, false)
|
|
53
66
|
return nil unless klass.is_a?(Class)
|
|
54
67
|
return nil unless klass.const_defined?(:QT_CLASS, false)
|
|
55
|
-
return nil unless klass <= Qt::QObject
|
|
56
68
|
|
|
57
69
|
klass
|
|
70
|
+
rescue NameError
|
|
71
|
+
nil
|
|
58
72
|
end
|
|
59
73
|
|
|
60
74
|
def instantiate_wrapper(klass, pointer)
|
|
61
75
|
wrapped = klass.allocate
|
|
62
76
|
wrapped.instance_variable_set(:@handle, pointer)
|
|
63
|
-
wrapped.init_children_tracking! if wrapped.respond_to?(:init_children_tracking!, true)
|
|
64
77
|
wrapped
|
|
65
78
|
end
|
|
66
79
|
|
|
80
|
+
def cached_wrapper_for(pointer)
|
|
81
|
+
wrapper_cache[pointer.address]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def register_wrapper(wrapper)
|
|
85
|
+
return wrapper unless wrapper.respond_to?(:handle)
|
|
86
|
+
|
|
87
|
+
pointer = wrapper.handle
|
|
88
|
+
return wrapper if null_pointer?(pointer)
|
|
89
|
+
return wrapper unless qobject_wrapper?(wrapper.class)
|
|
90
|
+
|
|
91
|
+
cached = cached_wrapper_for(pointer)
|
|
92
|
+
return cached if cached
|
|
93
|
+
|
|
94
|
+
cache_wrapper(wrapper)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def cache_wrapper(wrapper)
|
|
98
|
+
pointer = wrapper.handle
|
|
99
|
+
wrapper_cache[pointer.address] = wrapper
|
|
100
|
+
ensure_destroy_hook(wrapper, pointer)
|
|
101
|
+
wrapper
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def invalidate_cached_wrapper(pointer_or_address, expected_wrapper = nil)
|
|
105
|
+
address = pointer_or_address.is_a?(Integer) ? pointer_or_address : pointer_or_address.address
|
|
106
|
+
cached = wrapper_cache[address]
|
|
107
|
+
return unless cached
|
|
108
|
+
return if expected_wrapper && !cached.equal?(expected_wrapper)
|
|
109
|
+
|
|
110
|
+
wrapper_cache.delete(address)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def reset_cache!
|
|
114
|
+
@wrapper_cache = {}
|
|
115
|
+
@destroy_hook_addresses = {}
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def install_constructor_cache_hooks!
|
|
119
|
+
qobject_wrapper_classes.each do |klass|
|
|
120
|
+
next if klass.instance_variable_defined?(:@__qt_object_wrapper_constructor_hook_installed)
|
|
121
|
+
|
|
122
|
+
klass.prepend(ConstructorCacheHook)
|
|
123
|
+
klass.instance_variable_set(:@__qt_object_wrapper_constructor_hook_installed, true)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def wrapper_cache
|
|
128
|
+
@wrapper_cache ||= {}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def destroy_hook_addresses
|
|
132
|
+
@destroy_hook_addresses ||= {}
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def ensure_destroy_hook(wrapper, pointer)
|
|
136
|
+
address = pointer.address
|
|
137
|
+
return if destroy_hook_addresses[address]
|
|
138
|
+
|
|
139
|
+
destroy_hook_addresses[address] = true
|
|
140
|
+
Qt::EventRuntime.on_internal_signal(pointer, 'destroyed()') do |_payload|
|
|
141
|
+
destroy_hook_addresses.delete(address)
|
|
142
|
+
Qt::EventRuntime.clear_signal_registrations_for_address(address)
|
|
143
|
+
invalidate_cached_wrapper(address, wrapper)
|
|
144
|
+
end
|
|
145
|
+
rescue StandardError
|
|
146
|
+
destroy_hook_addresses.delete(address)
|
|
147
|
+
raise
|
|
148
|
+
end
|
|
149
|
+
|
|
67
150
|
def inheritance_depth(klass)
|
|
68
151
|
depth = 0
|
|
69
152
|
current = klass
|
|
@@ -73,5 +156,21 @@ module Qt
|
|
|
73
156
|
end
|
|
74
157
|
depth
|
|
75
158
|
end
|
|
159
|
+
|
|
160
|
+
def qobject_wrapper?(klass)
|
|
161
|
+
klass.is_a?(Class) && klass <= Qt::QObject
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def normalize_expected_qt_class(expected_qt_class)
|
|
165
|
+
return nil if expected_qt_class.nil?
|
|
166
|
+
|
|
167
|
+
value = expected_qt_class.to_s.strip
|
|
168
|
+
return nil if value.empty?
|
|
169
|
+
|
|
170
|
+
value = value.delete_prefix('Qt::')
|
|
171
|
+
return nil unless value.match?(/\A[A-Z]\w*\z/)
|
|
172
|
+
|
|
173
|
+
value
|
|
174
|
+
end
|
|
76
175
|
end
|
|
77
176
|
end
|
data/lib/qt/version.rb
CHANGED
data/lib/qt.rb
CHANGED
|
@@ -22,18 +22,23 @@ require_relative 'qt/constants'
|
|
|
22
22
|
require_relative 'qt/string_codec'
|
|
23
23
|
require_relative 'qt/date_time_codec'
|
|
24
24
|
require_relative 'qt/key_sequence_codec'
|
|
25
|
+
require_relative 'qt/object_list_codec'
|
|
25
26
|
require_relative 'qt/variant_codec'
|
|
26
27
|
require_relative 'qt/inspectable'
|
|
27
|
-
require_relative 'qt/children_tracking'
|
|
28
28
|
require_relative 'qt/object_wrapper'
|
|
29
29
|
require_relative 'qt/application_lifecycle'
|
|
30
30
|
require_relative 'qt/bridge'
|
|
31
31
|
require_relative 'qt/native'
|
|
32
|
+
require_relative 'qt/generated_setter_aliases_runtime'
|
|
33
|
+
require_relative 'qt/generated_singleton_forwarders_runtime'
|
|
32
34
|
require_relative 'qt/event_runtime_dispatch'
|
|
33
35
|
require_relative 'qt/event_runtime_qobject_methods'
|
|
34
36
|
require_relative 'qt/event_runtime'
|
|
35
37
|
require GENERATED_EVENT_PAYLOADS
|
|
36
38
|
require GENERATED_WIDGETS
|
|
39
|
+
Qt::GeneratedSetterAliasesRuntime.apply!(Qt)
|
|
40
|
+
Qt::GeneratedSingletonForwardersRuntime.apply!(Qt)
|
|
41
|
+
Qt::ObjectWrapper.install_constructor_cache_hooks!
|
|
37
42
|
require_relative 'qt/shortcut_compat'
|
|
38
43
|
Qt::GeneratedConstantsRuntime.apply_generated_scoped_constants!(Qt)
|
|
39
44
|
|
|
@@ -52,6 +52,7 @@ def map_cpp_arg_type(type_name, qt_class: nil, int_cast_types: nil)
|
|
|
52
52
|
return { ffi: :string, cast: :qdate_from_utf8 } if type == 'QDate'
|
|
53
53
|
return { ffi: :string, cast: :qtime_from_utf8 } if type == 'QTime'
|
|
54
54
|
return { ffi: :string, cast: :qkeysequence_from_utf8 } if type == 'QKeySequence'
|
|
55
|
+
return { ffi: :int, cast: :qcursor_shape } if type == 'QCursor'
|
|
55
56
|
return { ffi: :pointer, cast: :qicon_ref } if type == 'QIcon'
|
|
56
57
|
return { ffi: :string, cast: :qany_string_view } if type == 'QAnyStringView'
|
|
57
58
|
return { ffi: :string, cast: :qvariant_from_utf8 } if type == 'QVariant'
|
|
@@ -81,6 +82,7 @@ def map_scalar_cpp_return_type(type)
|
|
|
81
82
|
return { ffi_return: :int } if type == 'int'
|
|
82
83
|
return { ffi_return: :bool } if type == 'bool'
|
|
83
84
|
return { ffi_return: :string, return_cast: :qstring_to_utf8 } if type == 'QString'
|
|
85
|
+
return { ffi_return: :string, return_cast: :qobject_list_to_wrapped_array, object_list_class: 'QObject' } if type == 'QObjectList'
|
|
84
86
|
return { ffi_return: :string, return_cast: :qdatetime_to_utf8 } if type == 'QDateTime'
|
|
85
87
|
return { ffi_return: :string, return_cast: :qdate_to_utf8 } if type == 'QDate'
|
|
86
88
|
return { ffi_return: :string, return_cast: :qtime_to_utf8 } if type == 'QTime'
|
|
@@ -94,7 +96,7 @@ def map_pointer_cpp_return_type(type, ast: nil)
|
|
|
94
96
|
|
|
95
97
|
info = { ffi_return: :pointer }
|
|
96
98
|
base_type = type.sub(/\s*\*\z/, '').strip
|
|
97
|
-
if ast &&
|
|
99
|
+
if ast && ast_class_index(ast)[:methods_by_class].key?(base_type)
|
|
98
100
|
info[:pointer_class] = base_type
|
|
99
101
|
end
|
|
100
102
|
|
|
@@ -11,6 +11,7 @@ class CppMethodReturnEmitter
|
|
|
11
11
|
def emit
|
|
12
12
|
return emit_void if method[:ffi_return] == :void
|
|
13
13
|
return emit_qstring if qstring_return?
|
|
14
|
+
return emit_qobject_list if qobject_list_return?
|
|
14
15
|
return emit_qdatetime if qdatetime_return?
|
|
15
16
|
return emit_qdate if qdate_return?
|
|
16
17
|
return emit_qtime if qtime_return?
|
|
@@ -32,6 +33,10 @@ class CppMethodReturnEmitter
|
|
|
32
33
|
method[:ffi_return] == :string && method[:return_cast] == :qvariant_to_utf8
|
|
33
34
|
end
|
|
34
35
|
|
|
36
|
+
def qobject_list_return?
|
|
37
|
+
method[:ffi_return] == :string && method[:return_cast] == :qobject_list_to_wrapped_array
|
|
38
|
+
end
|
|
39
|
+
|
|
35
40
|
def qdatetime_return?
|
|
36
41
|
method[:ffi_return] == :string && method[:return_cast] == :qdatetime_to_utf8
|
|
37
42
|
end
|
|
@@ -62,6 +67,13 @@ class CppMethodReturnEmitter
|
|
|
62
67
|
lines << ' return utf8.constData();'
|
|
63
68
|
end
|
|
64
69
|
|
|
70
|
+
def emit_qobject_list
|
|
71
|
+
lines << " const QObjectList value = #{invocation};"
|
|
72
|
+
lines << ' thread_local QByteArray utf8;'
|
|
73
|
+
lines << ' utf8 = qobject_list_to_bridge_string(value).toUtf8();'
|
|
74
|
+
lines << ' return utf8.constData();'
|
|
75
|
+
end
|
|
76
|
+
|
|
65
77
|
def emit_qdatetime
|
|
66
78
|
lines << " const QDateTime value = #{invocation};"
|
|
67
79
|
lines << ' thread_local QByteArray utf8;'
|
|
@@ -19,6 +19,8 @@ def all_ffi_functions(specs, free_function_specs:)
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def append_constructor_ffi_function(fns, spec)
|
|
22
|
+
return if spec[:constructor][:mode] == :wrap_only
|
|
23
|
+
|
|
22
24
|
ctor_args = constructor_ffi_args(spec)
|
|
23
25
|
fns << { name: ctor_function_name(spec), ffi_return: :pointer, args: ctor_args }
|
|
24
26
|
end
|
|
@@ -160,7 +160,7 @@ def related_value_class_candidate?(ast, qt_class, all_classes, template_classes)
|
|
|
160
160
|
return false if abstract_class?(ast, qt_class)
|
|
161
161
|
return false if class_inherits?(ast, qt_class, 'QObject')
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
true
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
def related_qt_type_names(ast, qt_class)
|
|
@@ -178,11 +178,12 @@ end
|
|
|
178
178
|
|
|
179
179
|
def append_related_qt_types_from_decl(out, parsed, method_name)
|
|
180
180
|
candidates = []
|
|
181
|
-
candidates <<
|
|
182
|
-
parsed[:params].each { |param| candidates <<
|
|
183
|
-
candidates.each do |candidate|
|
|
181
|
+
candidates << [related_qt_type_name(parsed[:return_type]), parsed[:return_type].to_s] if parsed[:return_type]
|
|
182
|
+
parsed[:params].each { |param| candidates << [related_qt_type_name(param[:type]), param[:type].to_s] }
|
|
183
|
+
candidates.each do |candidate, raw_type|
|
|
184
184
|
next if candidate.empty? || !candidate.start_with?('Q')
|
|
185
|
-
next unless related_type_name_matches_method?(candidate, method_name)
|
|
185
|
+
next unless related_type_name_matches_method?(candidate, method_name) ||
|
|
186
|
+
(qt_pointer_type?(raw_type) && candidate.end_with?('Item'))
|
|
186
187
|
|
|
187
188
|
out << candidate
|
|
188
189
|
end
|
|
@@ -195,6 +196,14 @@ def related_type_name_matches_method?(qt_type, method_name)
|
|
|
195
196
|
method_name.to_s.downcase.include?(token)
|
|
196
197
|
end
|
|
197
198
|
|
|
199
|
+
def qt_pointer_type?(raw_type)
|
|
200
|
+
raw_type.to_s.strip.end_with?('*')
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def related_qt_type_name(raw_type)
|
|
204
|
+
normalized_cpp_type_name(raw_type).to_s.delete_suffix('*')
|
|
205
|
+
end
|
|
206
|
+
|
|
198
207
|
def discover_target_qt_classes(ast, scope)
|
|
199
208
|
all_classes = q_class_names(ast)
|
|
200
209
|
template_classes = template_qt_classes(ast)
|
|
@@ -220,9 +229,24 @@ def widget_target_qt_class?(ast, qt_class)
|
|
|
220
229
|
|
|
221
230
|
class_inherits?(ast, qt_class, 'QWidget') ||
|
|
222
231
|
class_inherits?(ast, qt_class, 'QLayout') ||
|
|
232
|
+
widget_item_target_qt_class?(ast, qt_class) ||
|
|
223
233
|
qt_class == 'QTableWidgetItem'
|
|
224
234
|
end
|
|
225
235
|
|
|
236
|
+
def widget_item_target_qt_class?(ast, qt_class)
|
|
237
|
+
return false unless qt_class.end_with?('Item')
|
|
238
|
+
return false if class_inherits?(ast, qt_class, 'QObject')
|
|
239
|
+
|
|
240
|
+
collect_constructor_decls(ast, qt_class).any? do |decl|
|
|
241
|
+
parsed = parse_method_signature(decl)
|
|
242
|
+
next false unless parsed
|
|
243
|
+
|
|
244
|
+
parsed[:params].any? do |param|
|
|
245
|
+
normalized_cpp_type_name(param[:type]).to_s.match?(/\AQ\w*Widget\*\z/)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
226
250
|
def qobject_target_qt_class?(ast, qt_class)
|
|
227
251
|
return false if qt_class.end_with?('Private')
|
|
228
252
|
return false if qt_class == 'QApplication'
|
|
@@ -264,8 +288,10 @@ def build_base_spec_for_qt_class(ast, qt_class)
|
|
|
264
288
|
parent_constructor_for_type(parent_type, widget_child)
|
|
265
289
|
elsif string_path_cast
|
|
266
290
|
string_path_constructor(string_path_cast)
|
|
267
|
-
|
|
291
|
+
elsif ctor_decls.any? { |decl| constructor_supports_no_args?(decl) }
|
|
268
292
|
{ parent: false }
|
|
293
|
+
else
|
|
294
|
+
{ parent: false, mode: :wrap_only }
|
|
269
295
|
end
|
|
270
296
|
base_spec_hash(qt_class, parent_ctor)
|
|
271
297
|
end
|
data/scripts/generate_bridge.rb
CHANGED
|
@@ -246,6 +246,7 @@ def arg_expr(arg)
|
|
|
246
246
|
when :qdate_from_utf8 then "qdate_from_bridge_value(#{arg[:name]})"
|
|
247
247
|
when :qtime_from_utf8 then "qtime_from_bridge_value(#{arg[:name]})"
|
|
248
248
|
when :qkeysequence_from_utf8 then "QKeySequence(as_qstring(#{arg[:name]}))"
|
|
249
|
+
when :qcursor_shape then "QCursor(static_cast<Qt::CursorShape>(#{arg[:name]}))"
|
|
249
250
|
when :qicon_ref then "*static_cast<QIcon*>(#{arg[:name]})"
|
|
250
251
|
when :qany_string_view then "QAnyStringView(as_qstring(#{arg[:name]}))"
|
|
251
252
|
when :qvariant_from_utf8 then "qvariant_from_bridge_value(#{arg[:name]})"
|
|
@@ -385,8 +386,10 @@ def generate_cpp_bridge(specs, free_function_specs)
|
|
|
385
386
|
end
|
|
386
387
|
|
|
387
388
|
def append_cpp_spec_methods(lines, spec)
|
|
388
|
-
|
|
389
|
-
|
|
389
|
+
unless spec[:constructor][:mode] == :wrap_only
|
|
390
|
+
generate_cpp_constructor(lines, spec)
|
|
391
|
+
lines << ''
|
|
392
|
+
end
|
|
390
393
|
spec[:methods].each do |method|
|
|
391
394
|
generate_cpp_method(lines, spec, method)
|
|
392
395
|
lines << ''
|
|
@@ -549,6 +552,14 @@ def cpp_bridge_prelude
|
|
|
549
552
|
const QByteArray fallback = value.toString().toUtf8().toBase64();
|
|
550
553
|
return QStringLiteral("qtv:str:") + QString::fromUtf8(fallback);
|
|
551
554
|
}
|
|
555
|
+
|
|
556
|
+
QString qobject_list_to_bridge_string(const QObjectList& value) {
|
|
557
|
+
QJsonArray array;
|
|
558
|
+
for (QObject* object : value) {
|
|
559
|
+
array.append(QString::number(reinterpret_cast<quintptr>(object)));
|
|
560
|
+
}
|
|
561
|
+
return QString::fromUtf8(QJsonDocument(array).toJson(QJsonDocument::Compact));
|
|
562
|
+
}
|
|
552
563
|
} // namespace
|
|
553
564
|
CPP
|
|
554
565
|
end
|
|
@@ -590,14 +601,19 @@ def ruby_api_metadata(methods)
|
|
|
590
601
|
ruby_method_names = methods.flat_map do |method|
|
|
591
602
|
ruby_name = ruby_safe_method_name(method[:ruby_name])
|
|
592
603
|
snake = to_snake(ruby_name)
|
|
593
|
-
snake == ruby_name ? [ruby_name] : [ruby_name, snake]
|
|
604
|
+
names = snake == ruby_name ? [ruby_name] : [ruby_name, snake]
|
|
605
|
+
names.concat(setter_alias_method_names(method))
|
|
606
|
+
names
|
|
594
607
|
end.uniq
|
|
595
608
|
properties = methods.filter_map { |method| method[:property] }.uniq
|
|
596
609
|
|
|
597
610
|
{
|
|
598
611
|
qt_method_names: qt_method_names,
|
|
599
612
|
ruby_method_names: ruby_method_names,
|
|
600
|
-
properties: properties
|
|
613
|
+
properties: properties,
|
|
614
|
+
setter_aliases: {},
|
|
615
|
+
singleton_setter_aliases: {},
|
|
616
|
+
singleton_forwarders: []
|
|
601
617
|
}
|
|
602
618
|
end
|
|
603
619
|
|
|
@@ -606,6 +622,9 @@ def append_ruby_class_api_constants(lines, qt_class:, metadata:, indent:)
|
|
|
606
622
|
lines << "#{indent}QT_API_QT_METHODS = #{metadata[:qt_method_names].inspect}.freeze"
|
|
607
623
|
lines << "#{indent}QT_API_RUBY_METHODS = #{metadata[:ruby_method_names].map(&:to_sym).inspect}.freeze"
|
|
608
624
|
lines << "#{indent}QT_API_PROPERTIES = #{metadata[:properties].map(&:to_sym).inspect}.freeze"
|
|
625
|
+
lines << "#{indent}QT_API_SETTER_ALIASES = #{metadata[:setter_aliases].inspect}.freeze"
|
|
626
|
+
lines << "#{indent}QT_API_SINGLETON_SETTER_ALIASES = #{metadata[:singleton_setter_aliases].inspect}.freeze"
|
|
627
|
+
lines << "#{indent}QT_API_SINGLETON_FORWARDERS = #{metadata[:singleton_forwarders].inspect}.freeze"
|
|
609
628
|
end
|
|
610
629
|
|
|
611
630
|
def ruby_method_arguments(method, arg_map, required_arg_count)
|
|
@@ -675,6 +694,9 @@ end
|
|
|
675
694
|
|
|
676
695
|
def ruby_native_method_body(method, rewritten_native_call)
|
|
677
696
|
return "Qt::StringCodec.from_qt_text(#{rewritten_native_call})" if method[:return_cast] == :qstring_to_utf8
|
|
697
|
+
if method[:return_cast] == :qobject_list_to_wrapped_array
|
|
698
|
+
return "Qt::ObjectListCodec.decode(#{rewritten_native_call}, '#{method[:object_list_class]}')"
|
|
699
|
+
end
|
|
678
700
|
return "Qt::VariantCodec.decode(#{rewritten_native_call})" if method[:return_cast] == :qvariant_to_utf8
|
|
679
701
|
return "Qt::DateTimeCodec.decode_qdatetime(#{rewritten_native_call})" if method[:return_cast] == :qdatetime_to_utf8
|
|
680
702
|
return "Qt::DateTimeCodec.decode_qdate(#{rewritten_native_call})" if method[:return_cast] == :qdate_to_utf8
|
|
@@ -694,8 +716,46 @@ def append_ruby_property_writer(lines, method:, indent:)
|
|
|
694
716
|
lines << "#{indent}alias_method :#{snake_property}=, :#{method[:property]}=" if snake_property != method[:property]
|
|
695
717
|
end
|
|
696
718
|
|
|
719
|
+
def setter_alias_base_name(method)
|
|
720
|
+
return nil unless method[:args].length == 1
|
|
721
|
+
return nil if method[:property]
|
|
722
|
+
|
|
723
|
+
return 'cursor' if method[:qt_name] == 'setCursor'
|
|
724
|
+
|
|
725
|
+
property_name_from_setter(method[:qt_name] || method[:ruby_name].to_s)
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
def setter_alias_method_names(method)
|
|
729
|
+
setter_alias_specs(method).keys
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
def setter_alias_specs(method)
|
|
733
|
+
base_name = setter_alias_base_name(method)
|
|
734
|
+
return {} unless base_name
|
|
735
|
+
|
|
736
|
+
ruby_target = ruby_public_method_name(base_name)
|
|
737
|
+
snake_target = to_snake(ruby_target)
|
|
738
|
+
setter_method_name = ruby_safe_method_name(method[:ruby_name])
|
|
739
|
+
aliases = { "#{ruby_target}=" => setter_method_name }
|
|
740
|
+
aliases["#{snake_target}="] = setter_method_name if snake_target != ruby_target
|
|
741
|
+
aliases
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
def qapplication_singleton_forwarder_names(methods, singleton_setter_aliases)
|
|
745
|
+
method_names = methods.flat_map do |method|
|
|
746
|
+
ruby_name = ruby_safe_method_name(method[:ruby_name])
|
|
747
|
+
snake_alias = to_snake(ruby_name)
|
|
748
|
+
snake_alias == ruby_name ? [ruby_name] : [ruby_name, snake_alias]
|
|
749
|
+
end
|
|
750
|
+
|
|
751
|
+
(method_names + singleton_setter_aliases.keys).uniq
|
|
752
|
+
end
|
|
753
|
+
|
|
697
754
|
def append_widget_initializer(lines, spec:, widget_root:, indent:)
|
|
698
|
-
if spec[:constructor][:mode] == :
|
|
755
|
+
if spec[:constructor][:mode] == :wrap_only
|
|
756
|
+
append_wrap_only_initializer(lines, spec, indent)
|
|
757
|
+
return
|
|
758
|
+
elsif spec[:constructor][:mode] == :string_path
|
|
699
759
|
append_string_path_initializer(lines, spec, indent)
|
|
700
760
|
elsif spec[:constructor][:mode] == :keysequence_parent
|
|
701
761
|
append_keysequence_parent_initializer(lines, spec, widget_root, indent)
|
|
@@ -709,10 +769,15 @@ def append_widget_initializer(lines, spec:, widget_root:, indent:)
|
|
|
709
769
|
lines << "#{indent}end"
|
|
710
770
|
end
|
|
711
771
|
|
|
772
|
+
def append_wrap_only_initializer(lines, spec, indent)
|
|
773
|
+
lines << "#{indent}def initialize(*)"
|
|
774
|
+
lines << "#{indent} raise NotImplementedError, '#{spec[:ruby_class]} cannot be directly instantiated yet'"
|
|
775
|
+
lines << "#{indent}end"
|
|
776
|
+
end
|
|
777
|
+
|
|
712
778
|
def append_parent_widget_initializer(lines, spec, widget_root, indent)
|
|
713
779
|
lines << "#{indent}def initialize(parent = nil)"
|
|
714
780
|
lines << "#{indent} @handle = Native.#{spec[:prefix]}_new(parent&.handle)"
|
|
715
|
-
lines << "#{indent} init_children_tracking!" if widget_root
|
|
716
781
|
append_parent_registration_logic(lines, spec, indent)
|
|
717
782
|
end
|
|
718
783
|
|
|
@@ -733,20 +798,15 @@ def append_keysequence_parent_initializer(lines, spec, widget_root, indent)
|
|
|
733
798
|
lines << "#{indent} key = nil"
|
|
734
799
|
lines << "#{indent} end"
|
|
735
800
|
lines << "#{indent} @handle = Native.#{spec[:prefix]}_new(Qt::KeySequenceCodec.encode(key), parent&.handle)"
|
|
736
|
-
lines << "#{indent} init_children_tracking!" if widget_root
|
|
737
801
|
append_parent_registration_logic(lines, spec, indent)
|
|
738
802
|
end
|
|
739
803
|
|
|
740
804
|
def append_parent_registration_logic(lines, spec, indent)
|
|
741
805
|
if spec[:ruby_class] == 'QWidget'
|
|
742
|
-
lines << "#{indent}
|
|
743
|
-
lines << "#{indent} parent.add_child(self)"
|
|
744
|
-
lines << "#{indent} else"
|
|
806
|
+
lines << "#{indent} unless parent"
|
|
745
807
|
lines << "#{indent} app = QApplication.current"
|
|
746
808
|
lines << "#{indent} app&.register_window(self)"
|
|
747
809
|
lines << "#{indent} end"
|
|
748
|
-
elsif spec[:constructor][:register_in_parent]
|
|
749
|
-
lines << "#{indent} parent.add_child(self) if parent&.respond_to?(:add_child)"
|
|
750
810
|
end
|
|
751
811
|
end
|
|
752
812
|
|
|
@@ -773,6 +833,13 @@ end
|
|
|
773
833
|
|
|
774
834
|
def generate_ruby_qapplication(lines, spec)
|
|
775
835
|
metadata = ruby_api_metadata(spec[:methods])
|
|
836
|
+
metadata[:singleton_setter_aliases] = Array(spec[:class_methods]).each_with_object({}) do |method, aliases|
|
|
837
|
+
aliases.merge!(setter_alias_specs(method))
|
|
838
|
+
end
|
|
839
|
+
metadata[:singleton_forwarders] = qapplication_singleton_forwarder_names(
|
|
840
|
+
Array(spec[:class_methods]),
|
|
841
|
+
metadata[:singleton_setter_aliases]
|
|
842
|
+
)
|
|
776
843
|
|
|
777
844
|
append_ruby_qapplication_prelude(lines, spec, metadata)
|
|
778
845
|
append_ruby_qapplication_singleton_accessors(lines)
|
|
@@ -826,6 +893,9 @@ end
|
|
|
826
893
|
|
|
827
894
|
def qapplication_class_method_body(method, native_call)
|
|
828
895
|
return " Qt::StringCodec.from_qt_text(#{native_call})" if method[:return_cast] == :qstring_to_utf8
|
|
896
|
+
if method[:return_cast] == :qobject_list_to_wrapped_array
|
|
897
|
+
return " Qt::ObjectListCodec.decode(#{native_call}, '#{method[:object_list_class]}')"
|
|
898
|
+
end
|
|
829
899
|
return " Qt::DateTimeCodec.decode_qdatetime(#{native_call})" if method[:return_cast] == :qdatetime_to_utf8
|
|
830
900
|
return " Qt::DateTimeCodec.decode_qdate(#{native_call})" if method[:return_cast] == :qdate_to_utf8
|
|
831
901
|
return " Qt::DateTimeCodec.decode_qtime(#{native_call})" if method[:return_cast] == :qtime_to_utf8
|
|
@@ -842,9 +912,7 @@ def generate_ruby_widget_class_header(lines, spec, metadata:, super_ruby:, class
|
|
|
842
912
|
append_ruby_class_api_constants(lines, qt_class: spec[:qt_class], metadata: metadata, indent: ' ')
|
|
843
913
|
lines << ''
|
|
844
914
|
lines << ' attr_reader :handle'
|
|
845
|
-
lines << ' attr_reader :children' if widget_root
|
|
846
915
|
lines << ' include Inspectable'
|
|
847
|
-
lines << ' include ChildrenTracking' if widget_root
|
|
848
916
|
lines << ' include EventRuntime::QObjectMethods' if qobject_based
|
|
849
917
|
lines << ''
|
|
850
918
|
end
|
|
@@ -883,7 +951,11 @@ end
|
|
|
883
951
|
def ruby_api_metadata_for_spec(spec, specs_by_qt, super_qt_by_qt)
|
|
884
952
|
inherited_methods = inherited_methods_for_spec(spec, specs_by_qt, super_qt_by_qt)
|
|
885
953
|
all_methods = (inherited_methods + spec[:methods]).uniq { |method| method[:qt_name] }
|
|
886
|
-
ruby_api_metadata(all_methods)
|
|
954
|
+
metadata = ruby_api_metadata(all_methods)
|
|
955
|
+
metadata[:setter_aliases] = all_methods.each_with_object({}) do |method, aliases|
|
|
956
|
+
aliases.merge!(setter_alias_specs(method))
|
|
957
|
+
end
|
|
958
|
+
metadata
|
|
887
959
|
end
|
|
888
960
|
|
|
889
961
|
def ruby_super_class_for_spec(spec, super_qt_by_qt, qt_to_ruby)
|
|
@@ -991,6 +1063,7 @@ def collect_enum_constants_for_scope(ast, target_scope, warnings = [])
|
|
|
991
1063
|
next unless node['kind'] == 'EnumDecl'
|
|
992
1064
|
next unless scope == target_scope
|
|
993
1065
|
|
|
1066
|
+
next_value = 0
|
|
994
1067
|
Array(node['inner']).each do |entry|
|
|
995
1068
|
next unless entry['kind'] == 'EnumConstantDecl'
|
|
996
1069
|
|
|
@@ -1000,9 +1073,14 @@ def collect_enum_constants_for_scope(ast, target_scope, warnings = [])
|
|
|
1000
1073
|
|
|
1001
1074
|
raw_value = ast_extract_first_value(entry)
|
|
1002
1075
|
value = parse_ast_integer_value(raw_value)
|
|
1003
|
-
|
|
1076
|
+
if value.nil?
|
|
1077
|
+
value = next_value
|
|
1078
|
+
else
|
|
1079
|
+
next_value = value
|
|
1080
|
+
end
|
|
1004
1081
|
|
|
1005
1082
|
append_constant_with_conflict_warning(constants, name, value, warnings, target_scope.join('::'))
|
|
1083
|
+
next_value = value + 1
|
|
1006
1084
|
end
|
|
1007
1085
|
end
|
|
1008
1086
|
|
|
@@ -1017,6 +1095,9 @@ def collect_qt_namespace_enum_constants(ast, warnings = [])
|
|
|
1017
1095
|
|
|
1018
1096
|
append_constant_with_conflict_warning(constants, alias_name, value, warnings, 'Qt::QEventAlias')
|
|
1019
1097
|
end
|
|
1098
|
+
collect_enum_constants_for_scope(ast, ['QCursor'], warnings).each do |name, value|
|
|
1099
|
+
append_constant_with_conflict_warning(constants, name, value, warnings, 'Qt::QCursorAlias')
|
|
1100
|
+
end
|
|
1020
1101
|
constants
|
|
1021
1102
|
end
|
|
1022
1103
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: qt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Maksim Veynberg
|
|
@@ -50,7 +50,6 @@ files:
|
|
|
50
50
|
- lib/qt.rb
|
|
51
51
|
- lib/qt/application_lifecycle.rb
|
|
52
52
|
- lib/qt/bridge.rb
|
|
53
|
-
- lib/qt/children_tracking.rb
|
|
54
53
|
- lib/qt/constants.rb
|
|
55
54
|
- lib/qt/date_time_codec.rb
|
|
56
55
|
- lib/qt/errors.rb
|
|
@@ -58,9 +57,12 @@ files:
|
|
|
58
57
|
- lib/qt/event_runtime_dispatch.rb
|
|
59
58
|
- lib/qt/event_runtime_qobject_methods.rb
|
|
60
59
|
- lib/qt/generated_constants_runtime.rb
|
|
60
|
+
- lib/qt/generated_setter_aliases_runtime.rb
|
|
61
|
+
- lib/qt/generated_singleton_forwarders_runtime.rb
|
|
61
62
|
- lib/qt/inspectable.rb
|
|
62
63
|
- lib/qt/key_sequence_codec.rb
|
|
63
64
|
- lib/qt/native.rb
|
|
65
|
+
- lib/qt/object_list_codec.rb
|
|
64
66
|
- lib/qt/object_wrapper.rb
|
|
65
67
|
- lib/qt/shortcut_compat.rb
|
|
66
68
|
- lib/qt/string_codec.rb
|
|
@@ -98,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
98
100
|
- !ruby/object:Gem::Version
|
|
99
101
|
version: '0'
|
|
100
102
|
requirements: []
|
|
101
|
-
rubygems_version:
|
|
103
|
+
rubygems_version: 4.0.9
|
|
102
104
|
specification_version: 4
|
|
103
105
|
summary: Ruby bindings for Qt 6.4.2+
|
|
104
106
|
test_files: []
|
data/lib/qt/children_tracking.rb
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Qt
|
|
4
|
-
# Child object tracking to mirror Qt parent/child ownership in Ruby.
|
|
5
|
-
module ChildrenTracking
|
|
6
|
-
def init_children_tracking!
|
|
7
|
-
@children = []
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def add_child(child)
|
|
11
|
-
@children ||= []
|
|
12
|
-
@children << child
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|