qt 0.1.9 → 0.2.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/ext/qt_ruby_bridge/extconf.rb +2 -0
- data/ext/qt_ruby_bridge/qt_ruby_runtime.hpp +14 -0
- data/ext/qt_ruby_bridge/runtime_events.cpp +8 -3
- data/ext/qt_ruby_bridge/runtime_value_types.cpp +22 -0
- data/ext/qt_ruby_bridge/runtime_virtual_methods.cpp +78 -0
- data/lib/qt/application_lifecycle.rb +1 -1
- data/lib/qt/event_runtime_dispatch.rb +2 -0
- data/lib/qt/generated_overload_runtime.rb +7 -0
- data/lib/qt/object_wrapper.rb +1 -0
- data/lib/qt/value_wrapper.rb +26 -0
- data/lib/qt/version.rb +1 -1
- data/lib/qt/virtual_method_runtime.rb +165 -0
- data/lib/qt.rb +4 -0
- data/scripts/generate_bridge/ast_introspection.rb +16 -3
- data/scripts/generate_bridge/auto_methods.rb +205 -24
- data/scripts/generate_bridge/cpp_method_return_emitter.rb +75 -24
- data/scripts/generate_bridge/ffi_api.rb +17 -1
- data/scripts/generate_bridge/free_function_specs.rb +0 -153
- data/scripts/generate_bridge/spec_discovery.rb +53 -13
- data/scripts/generate_bridge.rb +410 -31
- metadata +6 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dcd3d0dc3ef5c1d53209f273d6b5781b335c1dd11e9d3f41ddd1b709c7a61904
|
|
4
|
+
data.tar.gz: 31374c47b19b8c121904ffa042c13910e0512879a63dde9392f69ce0d6a81004
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '091c51ec3e5869a0acea502c8487e7bbecf45bf4f45549e26e06ee5eb95462a216e03e067dfb4081675e1ea94a662c4ee39a27a4d7adb80e7f8e6347ca45ac4f'
|
|
7
|
+
data.tar.gz: 4f5f4d68d1573229567c85b8835348e6e165e96f904583ae3e3b054f950dcaf324b9b6d8b912ecc49f13332af6f9009acddf8a670460e714dbdd172150825e03
|
|
@@ -60,6 +60,8 @@ runtime_hpp = File.expand_path('../../ext/qt_ruby_bridge/qt_ruby_runtime.hpp', _
|
|
|
60
60
|
runtime_cpp_files = %w[
|
|
61
61
|
runtime_events.cpp
|
|
62
62
|
runtime_signals.cpp
|
|
63
|
+
runtime_value_types.cpp
|
|
64
|
+
runtime_virtual_methods.cpp
|
|
63
65
|
].map { |name| File.expand_path("../../ext/qt_ruby_bridge/#{name}", __dir__) }
|
|
64
66
|
|
|
65
67
|
unless File.exist?(generated_cpp)
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include <QApplication>
|
|
4
|
+
#include <QByteArray>
|
|
5
|
+
#include <QList>
|
|
6
|
+
#include <QVariant>
|
|
4
7
|
|
|
5
8
|
namespace QtRubyRuntime {
|
|
6
9
|
using EventCallback = int (*)(void*, int, const char*);
|
|
7
10
|
using SignalCallback = void (*)(void*, int, const char*);
|
|
11
|
+
using VirtualMethodCallback = void* (*)(void*, int, const char*);
|
|
8
12
|
|
|
9
13
|
// Creates/owns the singleton QApplication used by the Ruby runtime bridge.
|
|
10
14
|
// The implementation records the creating thread as GUI thread for shutdown checks.
|
|
@@ -13,6 +17,10 @@ QApplication* qapplication_new(const char* argv0);
|
|
|
13
17
|
// Returns false when teardown is rejected by runtime safety checks.
|
|
14
18
|
bool qapplication_delete(void* app_handle);
|
|
15
19
|
|
|
20
|
+
// FFI-safe conversion for public Qt QList<int> API parameters and results.
|
|
21
|
+
QList<int> qint_list_from_variant(const QVariant& value);
|
|
22
|
+
QVariant qvariant_from_qint_list(const QList<int>& value);
|
|
23
|
+
|
|
16
24
|
void set_event_callback(void* callback_ptr);
|
|
17
25
|
void watch_qobject_event(void* object_handle, int event_type);
|
|
18
26
|
void unwatch_qobject_event(void* object_handle, int event_type);
|
|
@@ -20,4 +28,10 @@ void unwatch_qobject_event(void* object_handle, int event_type);
|
|
|
20
28
|
void set_signal_callback(void* callback_ptr);
|
|
21
29
|
int qobject_connect_signal(void* object_handle, const char* signal_name);
|
|
22
30
|
int qobject_disconnect_signal(void* object_handle, const char* signal_name);
|
|
31
|
+
|
|
32
|
+
void set_virtual_method_callback(void* callback_ptr);
|
|
33
|
+
void set_virtual_dispatch_enabled(void* object_handle, int enabled);
|
|
34
|
+
int virtual_dispatch_enabled(void* object_handle);
|
|
35
|
+
QByteArray dispatch_virtual_method(const void* object_handle, int method_id, const QByteArray& arguments);
|
|
36
|
+
bool ruby_virtual_method_active(const void* object_handle, int method_id);
|
|
23
37
|
} // namespace QtRubyRuntime
|
|
@@ -19,6 +19,7 @@ namespace QtRubyRuntime {
|
|
|
19
19
|
constexpr int kEventCallbackIgnore = 0;
|
|
20
20
|
constexpr int kEventCallbackContinue = 1;
|
|
21
21
|
constexpr int kEventCallbackConsume = 2;
|
|
22
|
+
constexpr int kEventCallbackReject = 3;
|
|
22
23
|
|
|
23
24
|
EventCallback& event_callback_ref() {
|
|
24
25
|
static EventCallback callback = nullptr;
|
|
@@ -234,6 +235,10 @@ class EventFilter : public QObject {
|
|
|
234
235
|
event->accept();
|
|
235
236
|
return true;
|
|
236
237
|
}
|
|
238
|
+
if (callback_result == kEventCallbackReject) {
|
|
239
|
+
event->ignore();
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
237
242
|
return QObject::eventFilter(watched, event);
|
|
238
243
|
}
|
|
239
244
|
};
|
|
@@ -244,10 +249,10 @@ EventFilter* event_filter_instance() {
|
|
|
244
249
|
}
|
|
245
250
|
|
|
246
251
|
void ensure_event_filter_installed() {
|
|
247
|
-
static
|
|
248
|
-
if (
|
|
252
|
+
static QApplication* installed_on = nullptr;
|
|
253
|
+
if (qApp && installed_on != qApp) {
|
|
249
254
|
qApp->installEventFilter(event_filter_instance());
|
|
250
|
-
|
|
255
|
+
installed_on = qApp;
|
|
251
256
|
}
|
|
252
257
|
}
|
|
253
258
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#include "qt_ruby_runtime.hpp"
|
|
2
|
+
|
|
3
|
+
namespace QtRubyRuntime {
|
|
4
|
+
QList<int> qint_list_from_variant(const QVariant& value) {
|
|
5
|
+
QList<int> result;
|
|
6
|
+
const QVariantList values = value.toList();
|
|
7
|
+
result.reserve(values.size());
|
|
8
|
+
for (const QVariant& entry : values) {
|
|
9
|
+
result.append(entry.toInt());
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
QVariant qvariant_from_qint_list(const QList<int>& value) {
|
|
15
|
+
QVariantList result;
|
|
16
|
+
result.reserve(value.size());
|
|
17
|
+
for (int entry : value) {
|
|
18
|
+
result.append(entry);
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
} // namespace QtRubyRuntime
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#include "qt_ruby_runtime.hpp"
|
|
2
|
+
|
|
3
|
+
#include <vector>
|
|
4
|
+
#include <unordered_set>
|
|
5
|
+
#include <mutex>
|
|
6
|
+
|
|
7
|
+
namespace QtRubyRuntime {
|
|
8
|
+
namespace {
|
|
9
|
+
struct ActiveVirtualMethod {
|
|
10
|
+
const void* object_handle;
|
|
11
|
+
int method_id;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
VirtualMethodCallback& virtual_method_callback_ref() {
|
|
15
|
+
static VirtualMethodCallback callback = nullptr;
|
|
16
|
+
return callback;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
std::vector<ActiveVirtualMethod>& active_virtual_methods() {
|
|
20
|
+
thread_local std::vector<ActiveVirtualMethod> active;
|
|
21
|
+
return active;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
std::unordered_set<const void*>& virtual_dispatch_objects() {
|
|
25
|
+
static std::unordered_set<const void*> objects;
|
|
26
|
+
return objects;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
std::mutex& virtual_dispatch_mutex() {
|
|
30
|
+
static std::mutex mutex;
|
|
31
|
+
return mutex;
|
|
32
|
+
}
|
|
33
|
+
} // namespace
|
|
34
|
+
} // namespace QtRubyRuntime
|
|
35
|
+
|
|
36
|
+
void QtRubyRuntime::set_virtual_method_callback(void* callback_ptr) {
|
|
37
|
+
virtual_method_callback_ref() = reinterpret_cast<VirtualMethodCallback>(callback_ptr);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void QtRubyRuntime::set_virtual_dispatch_enabled(void* object_handle, int enabled) {
|
|
41
|
+
if (!object_handle) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
std::lock_guard<std::mutex> lock(virtual_dispatch_mutex());
|
|
45
|
+
if (enabled != 0) {
|
|
46
|
+
virtual_dispatch_objects().insert(object_handle);
|
|
47
|
+
} else {
|
|
48
|
+
virtual_dispatch_objects().erase(object_handle);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
int QtRubyRuntime::virtual_dispatch_enabled(void* object_handle) {
|
|
53
|
+
std::lock_guard<std::mutex> lock(virtual_dispatch_mutex());
|
|
54
|
+
return virtual_dispatch_objects().find(object_handle) != virtual_dispatch_objects().end();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
QByteArray QtRubyRuntime::dispatch_virtual_method(const void* object_handle, int method_id, const QByteArray& arguments) {
|
|
58
|
+
VirtualMethodCallback callback = virtual_method_callback_ref();
|
|
59
|
+
if (!callback) {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
auto& active = active_virtual_methods();
|
|
64
|
+
active.push_back({object_handle, method_id});
|
|
65
|
+
void* response = callback(const_cast<void*>(object_handle), method_id, arguments.constData());
|
|
66
|
+
active.pop_back();
|
|
67
|
+
return response ? QByteArray(static_cast<const char*>(response)) : QByteArray();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
bool QtRubyRuntime::ruby_virtual_method_active(const void* object_handle, int method_id) {
|
|
71
|
+
const auto& active = active_virtual_methods();
|
|
72
|
+
for (auto it = active.rbegin(); it != active.rend(); ++it) {
|
|
73
|
+
if (it->object_handle == object_handle && it->method_id == method_id) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
@@ -7,6 +7,7 @@ module Qt
|
|
|
7
7
|
EVENT_RESULT_IGNORE = 0
|
|
8
8
|
EVENT_RESULT_CONTINUE = 1
|
|
9
9
|
EVENT_RESULT_CONSUME = 2
|
|
10
|
+
EVENT_RESULT_REJECT = 3
|
|
10
11
|
|
|
11
12
|
module_function
|
|
12
13
|
|
|
@@ -20,6 +21,7 @@ module Qt
|
|
|
20
21
|
return EVENT_RESULT_CONTINUE unless handlers && !handlers.empty?
|
|
21
22
|
|
|
22
23
|
results = handlers.map { |handler| handler.call(payload) }
|
|
24
|
+
return EVENT_RESULT_REJECT if results.include?(:reject)
|
|
23
25
|
return EVENT_RESULT_CONSUME if results.any? { |result| result == true || result == :consume }
|
|
24
26
|
return EVENT_RESULT_IGNORE if results.any? { |result| result == false || result == :ignore }
|
|
25
27
|
|
data/lib/qt/object_wrapper.rb
CHANGED
|
@@ -172,6 +172,7 @@ module Qt
|
|
|
172
172
|
destroy_hook_addresses.delete(address)
|
|
173
173
|
Qt::EventRuntime.clear_signal_registrations_for_address(address)
|
|
174
174
|
invalidate_cached_wrapper(address, wrapper)
|
|
175
|
+
wrapper.instance_variable_set(:@handle, nil) if wrapper.handle&.address == address
|
|
175
176
|
end
|
|
176
177
|
rescue StandardError
|
|
177
178
|
destroy_hook_addresses.delete(address)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Qt
|
|
4
|
+
# Owns copied Qt value objects returned through opaque FFI handles.
|
|
5
|
+
module ValueWrapper
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def wrap(handle, qt_class, delete_method)
|
|
9
|
+
return nil if handle.nil? || handle.null?
|
|
10
|
+
|
|
11
|
+
wrapper = Qt.const_get(qt_class).allocate
|
|
12
|
+
wrapper.instance_variable_set(:@handle, handle)
|
|
13
|
+
ObjectSpace.define_finalizer(wrapper, finalizer(delete_method, handle))
|
|
14
|
+
wrapper
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def finalizer(delete_method, handle)
|
|
18
|
+
proc do
|
|
19
|
+
Qt::Native.public_send(delete_method, handle) if Qt::Native.available?
|
|
20
|
+
rescue StandardError
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
private_class_method :finalizer
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/qt/version.rb
CHANGED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'weakref'
|
|
5
|
+
|
|
6
|
+
module Qt
|
|
7
|
+
# Dispatches generated C++ virtual overrides to methods defined by Ruby subclasses.
|
|
8
|
+
module VirtualMethodRuntime
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def install!(descriptors)
|
|
12
|
+
@descriptors = descriptors.to_h { |descriptor| [descriptor.fetch(:id), symbolize_keys(descriptor)] }
|
|
13
|
+
return if @callback
|
|
14
|
+
|
|
15
|
+
@callback = FFI::Function.new(:pointer, %i[pointer int string]) do |object_handle, method_id, payload|
|
|
16
|
+
dispatch(object_handle, method_id, payload)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def ensure_installed!
|
|
21
|
+
return if @native_installed
|
|
22
|
+
|
|
23
|
+
Native.define_bridge_wrappers!
|
|
24
|
+
Native.set_virtual_method_callback(@callback)
|
|
25
|
+
@native_installed = true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def attach(wrapper)
|
|
29
|
+
ensure_installed!
|
|
30
|
+
enabled = @descriptors&.values&.any? { |descriptor| overridden_method_name(wrapper, descriptor) }
|
|
31
|
+
handle = wrapper.handle
|
|
32
|
+
Native.set_virtual_dispatch_enabled(handle, enabled ? 1 : 0)
|
|
33
|
+
if enabled
|
|
34
|
+
wrapper_cache[handle.address] = WeakRef.new(wrapper)
|
|
35
|
+
else
|
|
36
|
+
wrapper_cache.delete(handle.address)
|
|
37
|
+
end
|
|
38
|
+
wrapper
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def dispatch(object_handle, method_id, payload)
|
|
42
|
+
descriptor = @descriptors&.[](method_id)
|
|
43
|
+
return callback_response(handled: false) unless descriptor
|
|
44
|
+
|
|
45
|
+
object_address = pointer_address(object_handle)
|
|
46
|
+
return callback_response(handled: false) if object_address.zero?
|
|
47
|
+
|
|
48
|
+
object_pointer = FFI::Pointer.new(object_address)
|
|
49
|
+
wrapper = ObjectWrapper.cached_wrapper_for(object_pointer) || cached_wrapper_for(object_address)
|
|
50
|
+
return callback_response(handled: false) unless wrapper
|
|
51
|
+
|
|
52
|
+
ruby_method = overridden_method_name(wrapper, descriptor)
|
|
53
|
+
return callback_response(handled: false) unless ruby_method
|
|
54
|
+
|
|
55
|
+
encoded_args = payload.nil? || payload.empty? ? [] : JSON.parse(StringCodec.from_qt_text(payload))
|
|
56
|
+
args = descriptor.fetch(:args).zip(encoded_args).map do |arg_descriptor, value|
|
|
57
|
+
decode_argument(arg_descriptor, value)
|
|
58
|
+
end
|
|
59
|
+
value = wrapper.__send__(ruby_method, *args)
|
|
60
|
+
callback_response(handled: true, value: encode_return(descriptor.fetch(:return), value))
|
|
61
|
+
rescue Exception => error # FFI callbacks must not unwind a Ruby exception through C++.
|
|
62
|
+
(@callback_errors ||= {})[Thread.current.object_id] = error
|
|
63
|
+
callback_response(handled: false)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def raise_pending_error!
|
|
67
|
+
error = @callback_errors&.delete(Thread.current.object_id)
|
|
68
|
+
raise error if error
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def after_native_call(result)
|
|
72
|
+
raise_pending_error!
|
|
73
|
+
result
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def decode_argument(descriptor, value)
|
|
77
|
+
case descriptor.fetch(:kind)
|
|
78
|
+
when :integer then Integer(value)
|
|
79
|
+
when :boolean then value == true
|
|
80
|
+
when :string then value
|
|
81
|
+
when :pointer, :value then wrap_borrowed_pointer(value, descriptor[:qt_class])
|
|
82
|
+
else raise ArgumentError, "unsupported virtual argument kind: #{descriptor[:kind].inspect}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def wrap_borrowed_pointer(value, qt_class)
|
|
87
|
+
address = value.nil? ? 0 : Integer(value)
|
|
88
|
+
return nil if address.zero?
|
|
89
|
+
|
|
90
|
+
pointer = FFI::Pointer.new(address)
|
|
91
|
+
klass = Qt.const_get(qt_class, false)
|
|
92
|
+
return ObjectWrapper.wrap(pointer, qt_class) if klass <= QObject
|
|
93
|
+
|
|
94
|
+
wrapper = klass.allocate
|
|
95
|
+
wrapper.instance_variable_set(:@handle, pointer)
|
|
96
|
+
wrapper
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def encode_return(descriptor, value)
|
|
100
|
+
case descriptor.fetch(:kind)
|
|
101
|
+
when :void then nil
|
|
102
|
+
when :integer
|
|
103
|
+
Integer(value)
|
|
104
|
+
when :boolean
|
|
105
|
+
value == true
|
|
106
|
+
when :string
|
|
107
|
+
value.nil? ? '' : String(value)
|
|
108
|
+
when :pointer, :value
|
|
109
|
+
return nil if value.nil?
|
|
110
|
+
raise TypeError, 'Qt pointer return must be a wrapper with a handle' unless value.respond_to?(:handle)
|
|
111
|
+
|
|
112
|
+
value.handle.address.to_s
|
|
113
|
+
else raise ArgumentError, "unsupported virtual return kind: #{descriptor[:kind].inspect}"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def callback_response(handled:, value: nil)
|
|
118
|
+
response = JSON.generate(handled: handled, value: value)
|
|
119
|
+
buffer = FFI::MemoryPointer.from_string(response)
|
|
120
|
+
(@callback_buffers ||= {})[Thread.current.object_id] = buffer
|
|
121
|
+
buffer
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def overridden_method_name(wrapper, descriptor)
|
|
125
|
+
wrapper_class = Qt.const_get(descriptor.fetch(:wrapper_class), false)
|
|
126
|
+
return nil unless wrapper.class.ancestors.include?(wrapper_class)
|
|
127
|
+
|
|
128
|
+
candidates = [descriptor.fetch(:ruby_name).to_sym, descriptor.fetch(:snake_name).to_sym].uniq
|
|
129
|
+
wrapper.class.ancestors.take_while { |ancestor| ancestor != wrapper_class }.each do |ancestor|
|
|
130
|
+
candidates.each do |candidate|
|
|
131
|
+
methods = ancestor.instance_methods(false) + ancestor.private_instance_methods(false)
|
|
132
|
+
return candidate if methods.include?(candidate)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
nil
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def wrapper_cache
|
|
139
|
+
@wrapper_cache ||= {}
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def cached_wrapper_for(address)
|
|
143
|
+
reference = wrapper_cache[address]
|
|
144
|
+
reference&.__getobj__
|
|
145
|
+
rescue WeakRef::RefError
|
|
146
|
+
wrapper_cache.delete(address)
|
|
147
|
+
nil
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def pointer_address(pointer)
|
|
151
|
+
return 0 if pointer.nil?
|
|
152
|
+
return pointer.address if pointer.respond_to?(:address)
|
|
153
|
+
|
|
154
|
+
Integer(pointer)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def symbolize_keys(value)
|
|
158
|
+
case value
|
|
159
|
+
when Hash then value.to_h { |key, nested| [key.to_sym, symbolize_keys(nested)] }
|
|
160
|
+
when Array then value.map { |nested| symbolize_keys(nested) }
|
|
161
|
+
else value
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
data/lib/qt.rb
CHANGED
|
@@ -24,6 +24,7 @@ require_relative 'qt/date_time_codec'
|
|
|
24
24
|
require_relative 'qt/key_sequence_codec'
|
|
25
25
|
require_relative 'qt/object_list_codec'
|
|
26
26
|
require_relative 'qt/variant_codec'
|
|
27
|
+
require_relative 'qt/value_wrapper'
|
|
27
28
|
require_relative 'qt/inspectable'
|
|
28
29
|
require_relative 'qt/object_wrapper'
|
|
29
30
|
require_relative 'qt/application_lifecycle'
|
|
@@ -31,11 +32,14 @@ require_relative 'qt/bridge'
|
|
|
31
32
|
require_relative 'qt/native'
|
|
32
33
|
require_relative 'qt/generated_setter_aliases_runtime'
|
|
33
34
|
require_relative 'qt/generated_singleton_forwarders_runtime'
|
|
35
|
+
require_relative 'qt/generated_overload_runtime'
|
|
36
|
+
require_relative 'qt/virtual_method_runtime'
|
|
34
37
|
require_relative 'qt/event_runtime_dispatch'
|
|
35
38
|
require_relative 'qt/event_runtime_qobject_methods'
|
|
36
39
|
require_relative 'qt/event_runtime'
|
|
37
40
|
require GENERATED_EVENT_PAYLOADS
|
|
38
41
|
require GENERATED_WIDGETS
|
|
42
|
+
Qt::VirtualMethodRuntime.install!(Qt::GENERATED_VIRTUAL_METHODS)
|
|
39
43
|
Qt::GeneratedSetterAliasesRuntime.apply!(Qt)
|
|
40
44
|
Qt::GeneratedSingletonForwardersRuntime.apply!(Qt)
|
|
41
45
|
Qt::ObjectWrapper.install_constructor_cache_hooks!
|
|
@@ -55,7 +55,10 @@ class AstClassMemberRecorder
|
|
|
55
55
|
return false unless inner['kind'] == 'CXXMethodDecl' && inner['name']
|
|
56
56
|
|
|
57
57
|
access = inner['access'] || current_access
|
|
58
|
-
@methods_by_class[@class_name][inner['name']] << inner.merge(
|
|
58
|
+
@methods_by_class[@class_name][inner['name']] << inner.merge(
|
|
59
|
+
'__effective_access' => access,
|
|
60
|
+
'__owner_class' => @class_name
|
|
61
|
+
)
|
|
59
62
|
true
|
|
60
63
|
end
|
|
61
64
|
|
|
@@ -172,7 +175,8 @@ def ast_class_index_constructor_collections
|
|
|
172
175
|
{
|
|
173
176
|
ctors_by_class: Hash.new { |h, k| h[k] = [] },
|
|
174
177
|
ctor_decls_by_class: Hash.new { |h, k| h[k] = [] },
|
|
175
|
-
abstract_by_class: Hash.new(false)
|
|
178
|
+
abstract_by_class: Hash.new(false),
|
|
179
|
+
final_by_class: Hash.new(false)
|
|
176
180
|
}
|
|
177
181
|
end
|
|
178
182
|
|
|
@@ -189,6 +193,8 @@ def ast_index_track_record_decl(node, data)
|
|
|
189
193
|
return if class_name.nil? || class_name.empty?
|
|
190
194
|
|
|
191
195
|
data[:abstract_by_class][class_name] ||= node.dig('definitionData', 'isAbstract') == true
|
|
196
|
+
data[:final_by_class][class_name] ||= node['final'] == true ||
|
|
197
|
+
Array(node['inner']).any? { |child| child['kind'] == 'FinalAttr' }
|
|
192
198
|
ast_record_base_classes(node, class_name, data[:bases_by_class])
|
|
193
199
|
method_count, ctor_count = ast_record_class_members(
|
|
194
200
|
node, class_name, data[:methods_by_class], data[:ctors_by_class], data[:ctor_decls_by_class]
|
|
@@ -202,7 +208,14 @@ def finalize_ast_class_index!(data)
|
|
|
202
208
|
data[:ctors_by_class].each_value(&:uniq!)
|
|
203
209
|
debug_log("ast_class_index classes=#{data[:methods_by_class].length} method_decls=#{data[:method_decl_count]}")
|
|
204
210
|
debug_log("ast_class_index ctor_decls=#{data[:ctor_decl_count]}")
|
|
205
|
-
data.slice(
|
|
211
|
+
data.slice(
|
|
212
|
+
:methods_by_class,
|
|
213
|
+
:bases_by_class,
|
|
214
|
+
:ctors_by_class,
|
|
215
|
+
:ctor_decls_by_class,
|
|
216
|
+
:abstract_by_class,
|
|
217
|
+
:final_by_class
|
|
218
|
+
)
|
|
206
219
|
end
|
|
207
220
|
|
|
208
221
|
def ast_class_index(ast)
|